Rails 3: How to create a named scope based on Controller's method?
In my ApplicationController
I have the demo_mode?
method (which returns true
when the currently logged in user type is "demo").
Post
model has the publisher_id
field, which refers开发者_如何转开发 to Users
table.
User
has the user_type
field, one of the possible values of which is "demo".
Bottom line: post p
was published by a "demo" user if and only if:
User.find(p.publisher_id).user_type == "demo"
I would like to create a named scope Post.relevant
that will return:
- all posts that were published by "demo" users, if
demo_mode? == true
- all posts that were published by non "demo" users, if
demo_mode? == false
How would you create such a named scope ? Should I move demo_mode?
to other place ?
Use a lambda to make a dynamic scope, and keep the session info out of the model:
In your model:
class Post < ActiveRecord::Base
scope :relevant, lambda {|demo_mode|
joins(:publisher).
where("publishers.user_type #{demo_mode ? '' : 'NOT'} LIKE 'demo'")
}
end
And then in the controller:
posts = Post.relevant(demo_mode?)
Try something like this
class Post < ActiveRecord::Base
scope :relevant, joins("INNER JOIN users ON (users.user_type = 'demo')").where("publisher_id = users.id")
end
If I understand correctly, the demo state is determined by the session so only the controller knows about it. On the other hand, the controller (or possibly the view) is the only place where you would want to query the scope. If all of this is correct, I would add a method to ApplicationController like this:
class ApplicationController < ActionController::Base
def relevant_posts
Post.joins(:publisher).
where("publishers.user_type #{demo_mode? ? '' : 'NOT'} LIKE 'demo'")
end
...
helper_method :relevant_posts # if you want it to be available in views
end
Technically, this is not a named scope. Rails 3, however does not make much of a difference between named scopes and the standard query interface.
精彩评论