あなたは私にアイデアを与えました:
models / user.rb:
class User < ActiveRecord::Base
has_many :posts
attr_accessible :name
end
models / post.rb:
class Post < ActiveRecord::Base
belongs_to :user
attr_accessible :title, :user_id
end
コントローラ/posts_controller.rb:
class PostsController < ApplicationController
belongs_to :user # creates belongs_to_user filter
# @posts = Post.all # managed by belongs_to_user filter
# GET /posts
# GET /posts.json
def index
respond_to do |format|
format.html # index.html.erb
format.json { render json: @posts }
end
end
end
そして今、実体:
controllers / application_controller.rb:
class ApplicationController < ActionController::Base
protect_from_forgery
def self.belongs_to(model)
# Example: model == :user
filter_method_name = :"belongs_to_#{model}_index" # :belongs_to_user_index
foreign_key = "#{model}_id" # 'user_id'
model_class = model.to_s.classify # User
class_eval <<-EOV, __FILE__, __LINE__ + 1
def #{filter_method_name} # def belongs_to_user_index
if params.has_key? :'#{foreign_key}' # if params.has_key? :user_id
instance_variable_set :"@#{model}", # instance_variable_set :"@user",
#{model_class}.find(params[:'#{foreign_key}']) # User.find(params[:user_id])
instance_variable_set :"@\#{controller_name}", # instance_variable_set :"@#{controller_name}",
@#{model}.send(controller_name.pluralize) # @user.send(controller_name.pluralize)
else # else
instance_variable_set :"@\#{controller_name}", # instance_variable_set :"@#{controller_name}",
controller_name.classify.constantize.all # controller_name.classify.constantize.all
end # end
end # end
EOV
before_filter filter_method_name, only: :index # before_filter :belongs_to_user_index, only: :index
end
end
Rubyメタプログラミングの概念がある場合、コードを理解するのは複雑ではありません。コントローラー名と関連付けから名前を推測するインスタンス変数を宣言するbefore_filterを宣言します。複数インスタンス変数バージョンを使用する唯一のアクションであるインデックスアクションに対してのみ実装されますが、他のアクションのフィルターバージョンを簡単に記述できるはずです。