スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

Railsで複数のWebを管理してみる

ユーザが使うWebと管理者が使うWebを作りたい時に別々に作るとModelやViewの共通化がやりにくくなります。
だけど1つにした時にControllerやViewがユーザと管理者と同じ階層に入るのは使いにくいです。
そこで、ControllerとViewはディレクトリを分けて扱うことにします。
Modelはユーザと管理者であまり変わらないので1つの階層で扱います。

例えばprojectを扱う場合以下のコマンドで雛形を生成します。

rails g model projects nm:text
rails g scaffold_controller admin/projects
rails g scaffold_controller user/projects

routeは以下のようにします。

namespace :admin, path: "administrator" do
resources :projects
end
namespace :user, path: "" do
resources :projects
end


管理者は
http://localhost/administrator/projects
ユーザは
http://localhost/projects
でアクセスできます。

階層を好きなように切っても、後でrouteで実際のURLを調整できるのが便利です。
管理者のアクセスではIPアドレス制限したい場合などは
ユーザと管理者で別々にRailsを起動して、nginx等でIPアドレスを制限するのがよいです。

Railsの本番環境用ログ設定

Railsで本番環境を想定したログの設定例です。
ログをためすぎてディスクを圧迫しないことと、
必要なログは残しておくこと、
重要なログはメールで送信することを想定しています。
この設定ではRailsを動かす仕組みとtd-agentだけあればいいので
シンプルなサーバ構成になっています。

以下の手順で行います。
1. ログローテート
2. ログから改行を取り除く
3. 必要なものだけメール送信

1. ログローテート
Loggerのコンストラクタでは第二引数に残すファイルの数
第三引数にログのファイルサイズが指定できます。

vi config/environments/production.rb

config.logger = Logger.new("log/production.log", 10, 1 * 1024 * 1024)

2. ログから改行を取り除く
Fatalエラーが発生した場合では通常のログだと改行されて出力されます。
それだと後でメールを送るための仕組みがうまく検知できないので、改行を取り除きます。

vi config/environments/production.rb

config.log_formatter = ::Logger::Formatter.new

vi config/environment.rb

class Logger
class Formatter
def call(severity, time, progname, msg)
if msg.class.to_s == "String"
msg = msg.gsub(/\n/, "")
if msg.present? && !msg.include?("assets") && !msg.include?("erb")
format = "[%s %d] %5s -- %s: \'%s\'\n"
format % ["#{time.strftime('%Y-%m-%dT%H:%M:%S')}.#{'%06d' % time.usec.to_s}",$$, severity, progname, msg2str(msg)]
end
end
end
end
end

3. 必要なものだけメール送信
td-agentを使ってログファイルを監視して
必要なものだけメールで送信します。
メールの送信はAWSのSNSを利用しています。

・td-agentにプラグイン追加
sudo /usr/sbin/td-agent-gem update
sudo /usr/sbin/td-agent-gem clean
sudo /usr/sbin/td-agent-gem install fluent-plugin-tail-ex
sudo /usr/sbin/td-agent-gem install fluent-plugin-sns
sudo /usr/sbin/td-agent-gem install fluent-plugin-rewrite-tag-filter

・td-agentの設定
sudo vi /etc/td-agent/td-agent.conf
<source>
type tail_ex
path /home/ubuntu/var/www/apps/web/log/*.log
pos_file /var/log/td-agent/web.log.pos
tag web.raw
format /\[(?<time>[^ ]*) (?<pid>[^\]]*)\] +(?<level>[^ ]+) -- : (?<content>.*)$/
time_format %Y-%m-%dT%H:%M:%S.%L
refresh_interval 300
</source>
<match web.raw>
type rewrite_tag_filter
rewriterule1 content ActionController::RoutingError clear
rewriterule2 level FATAL web.error
rewriterule3 level ERROR web.error
rewriterule4 level WARN web.error
rewriterule5 level .+ clear
</match>
<match web.error>
type sns
sns_topic_name web
aws_key_id xxxxxxxxxx
aws_sec_key xxxxxxxxxx
sns_endpoint sns.ap-northeast-1.amazonaws.com
sns_subject [web]error occerd
</match>
<match clear>
type null
</match>

railsをthinで本番リリースする

やること。
1. railsアプリ準備
2. thin設定
3. upstart設定
4. nginx設定
5. logrotate設定

1. railsアプリ準備
mkdir -p /home/user/var/www/apps
# railsアプリをデプロイ、ここではwebとする
cd /home/user/var/www/apps/web
bundle install --path=vendor/bundler
bundle exec rake assets:precompile

2. thin設定
bundle exec thin config -C thin.yaml
vi thin.yaml

environment: production
daemonize: false


3. upstart設定
sudo vi /etc/init/web.conf

description "web"
version "1.0"

env LANG=ja_JP.UTF-8
env SECRET_KEY_BASE=123456789

start on runlevel [2345] and started networking
stop on runlevel [!2345] and stopped networking

chdir /home/user/var/www/apps/web
setuid user
setgid user
exec bash -c '/home/user/.rbenv/shims/bundle exec thin start -C thin.yaml'

respawn
respawn limit 1 10

sudo start web

4. nginx設定
sudo vi /etc/nginx/sites-available/web

server {
listen 80;
server_name web.example.com;
return 301 https://$host$request_uri;
}

server {
listen 443 ssl;
ssl_certificate ssl/server.crt;
ssl_certificate_key ssl/server.key;
server_name web.example.com;

access_log /var/log/nginx/web_access.log;
error_log /var/log/nginx/web_error.log;
root /home/user/var/www/apps/web/public;
index index.html;

location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
try_files /system/maintenance.html $uri $uri/index.html $uri.html @ruby;
}

location @ruby {
proxy_pass http://localhost:3000;
}
}

sudo restart nginx

5. logrotate設定
vi /etc/logrotate.d/web

/home/user/var/www/apps/web/log/*.log {
weekly
missingok
rotate 52
compress
delaycompress
notifempty
copytruncate
}

Railsで論理削除したレコードを見ない方法

deleted_atというTIMESTAMPTZなカラムに日付が入っている場合は削除済み、NULLの場合は有効という論理削除を考えます。
projectsとimagesというテーブルがあり、1対Nの関係があります。

1. 有効なレコードを検索する
Project.all
してしまうと論理削除されたレコードまで取れます。
そこでこうします。
Project.where('deleted_at IS NULL').all

2. has_manyで取得する
has_manyもそのままだとダメなので条件を追加します。

def Project < ActiveRecord::Base
has_many :images, ->{where("#{Image.table_name}.deleted_at IS NULL")}
end


3. deviseでも論理削除対応
モデルクラスに以下を追加

def self.find_first_by_auth_conditions(warden_conditions)
where(warden_conditions).where('deleted_at IS NULL').first
end

RailsでMigrationで主キーをBIGINTにする等

DBはPostgreSQLを想定しています。
以下のコマンドでnmというカラムを持ったprojectsテーブルを作るRailsのコマンドを実行します。
bundle exec rails g model project nm:string

作成されたファイルは以下の通りです。

class CreateProjects < ActiveRecord::Migration
def change
create_table :projects do |t|
t.string :nm

t.timestamps null: false
end
end
end

この内容では主キーのidがINTで作成されます。
またcreated_at, updated_atもTIMESTAMPで作成されます。
しかしここではidはBIGINT, created_at, updated_atはTIMESTAMPTZ作成したいです。
そこで作成されたこのファイルを手で書き換えます。
他にも自分がよく使うカラムを追加します。
created_id, updated_id, deleted_idは処理した人のid
created_pg, updated_pg, deleted_pgは処理したプログラム名
deleted_atは削除した日時
bkは備考です。

class CreateProjects < ActiveRecord::Migration
def change
create_table :projects, id: false do |t|
t.column :id, 'BIGSERIAL PRIMARY KEY'

t.text :nm, null: false, default: ''

t.column :created_id, 'BIGINT', null: false, default: 0
t.column :updated_id, 'BIGINT', null: false, default: 0
t.column :deleted_id, 'BIGINT', null: false, default: 0

t.text :created_pg, null: false, default: ''
t.text :updated_pg, null: false, default: ''
t.text :deleted_pg, null: false, default: ''

t.column :created_at, 'TIMESTAMPTZ', null: false
t.column :updated_at, 'TIMESTAMPTZ', null: false
t.column :deleted_at, 'TIMESTAMPTZ'

t.text :bk
end
end
end
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。