非ActiveRecordの検証エラーメッセージをローカライズする
ActiveRecordを継承しないクラスに対し、バリデーションとそのエラーメッセージをローカライズする方法。
(1)バリデーション機能を持つクラスの実装
ポイントは冒頭のmixin。これによりActiveRecordのような振る舞いが可能となり、validatesメソッドが使えるようになる。
また、後述のform_forヘルパーにこのクラスのインスタンスを渡すとpersisted?メソッドが呼び出されるので、persisted?の定義も必要。
class Import::CSV include ActiveModel::Validations include ActiveModel::Conversion attr_accessor :file validates :file, :presence => true def persisted?; false; end end
(2)ビューの実装
form_forの引数@csvは(1)のインスタンス。ポイントは特になく、いたって普通にActiveRecordのフォームを実装する感じで実装する。
<%= form_for(@csv, :url => import_csv_path, :multipart => true) do |f| %> <% if @csv.errors.any? %> <div id="error_explanation"> <h2><%= pluralize(@csv.errors.count, "error") %> prohibited this csv from being saved:</h2> <ul> <% @csv.errors.full_messages.each do |msg| %> <li><%= msg %></li> <% end %> </ul> </div> <% end %> <div class="field"> <%= f.label :file %> <%= f.file_field :file %> </div> <div class="actions"> <%= f.submit 'confirm' %> </div> <% end %>
(3)ロケールファイルの実装
ポイントはActiveRecordではなく、ActiveModelをmixinしたクラスなのでキーはactivemodel配下に設定すること。それ以外はActiveRecordと同様。
尚、本題から逸れるけどネームスペースを持つクラスは以下のようにスラッシュ(Import::CSV => import/csv)で表す。
ja: activemodel: attributes: import/csv: file: CSVファイル errors: messages: blank: "を入力してください。"
以上
IE7でファイルをダウンロードする際、ファイル名が文字化けする問題
この問題はファイル名をURLエンコードすると解決する。
if request.env['HTTP_USER_AGENT'] =~ /MSIE 7/ file_name = ERB::Util.url_encode(file_name) end
自己解決 インポートにRESTなURL
(前日の日記の続き)
HTTPメソッドで単数、複数を表せないのならリソースで表す他ない。
ということで
インポート開始画面
GET /import/customers/new
インポート実行
POST /import/customers
良い感じだと思うな。
インポートにRESTなURL
Railsで何かしらのリソースをインポートする際のURLはどのようにしたらRESTになるのか?それがわからないという話。
<顧客情報のインポートを仮定した場合>
リソースは何か?→顧客
操作は何か?→リソースの作成
そのURLは?→POST /customers
↓
これだと単一リソースを作成する場合と変わらないのでボツ。
そこでインポートを名詞として解釈してみる
リソースは何か?→顧客のインポート???
操作は何か?→顧客のインポートを作成???
↓
リソースの時点でおかしい。作成するのは顧客のインポートではなくて顧客なのでボツ。
つまるところ問題はURLとそのHTTPメソッドを決定するパラメータが「リソース」と「操作」の2つしかなく、「操作」で表されるリソースの作成はそれによって作成されるリソース数に区別がないことなんじゃないかな?
という訳で冒頭の結論に到る。わからない。
どなたか解をご存知の方、助言頂けると幸いです。
同じアソシエーションを複数回定義するとaccepts_nested_attributes_forで既存レコードの保存ができなくなる
# ex class Diary < ActiveRecord::Base has_many :comments has_many :comments accepts_nested_attributes_for :comments
このようにするとDiaryインスタンスからcommentsアソシエーションをまとめて保存することができなくなる。
保存できないのは既存commentsで新たに追加したcommentsは保存される。
accepts_nested_attributes_forで子から親もまとめて作成できる
ポイントは2つ
①子のモデルにaccepts_nested_attributes_forを定義
class Child belongs_to :parent accepts_nested_attributes_for :parent end
②fields_forで親のフィールドオブジェクトを生成する際に親のフィールドのname属性を自力で指定する。
親から子の場合、自動で語尾に_attributesと付くが、子から親の場合何故か付かないので自力で_attributesを指定する。
<%= f.fields_for 'parent_attributes', @child.parent do |parent_f| %> <% end %>