开发者

Rails: Why is with_exclusive_scope protected? Any good practice on how to use it?

Given a model with default_scope to filter all outdated entries:

# == Schema Information
#
#  id          :integer(4)      not null, primary key
#  user_id     :integer(4)      not null, primary key
#  end_date    :datetime        

class Ticket < ActiveRecord::Base
  belongs_to :user
  default_scope :conditions => "tickets.end_date > NOW()"
end

Now I want to get any ticket. In this case with_exclusive_scope is the way to go, but is this method protected? Only this works:

 Ticke开发者_如何学Got.send(:with_exclusive_scope) { find(:all) }

Kind of a hack, isn't? So what's the right way to use? Especially when dealing with associations, it's getting even worse (given a user has many tickets):

 Ticket.send(:with_exclusive_scope) { user.tickets.find(:all) }

That's so ugly!!! - can't be the rails-way!?


FYI for anyone looking for the Rails3 way of doing this, you can use the unscoped method:

Ticket.unscoped.all


Avoid default_scope if possible. I think you should really re-ask yourself why you need a default_scope. Countering a default_scope is often messier than it's worth and it should only be used in rare cases. Also, using default_scope isn't very revealing when ticket associations are accessed outside the Ticket model (e.g. "I called account.tickets. Why aren't my tickets there?"). This is part of the reason why with_exclusive_scope is protected. You should taste some syntactic vinegar when you need to use it.

As an alternative, use a gem/plugin like pacecar that automatically adds useful named_scopes to your models giving you more revealing code everywhere. For Example:

class Ticket < ActiveRecord::Base
  include Pacecar
  belongs_to :user
end

user.tickets.ends_at_in_future # returns all future tickets for the user
user.tickets                   # returns all tickets for the user

You can also decorate your User model to make the above code cleaner:

Class User < ActiveRecord::Base
  has_many :tickets

  def future_tickets
    tickets.ends_at_in_future
  end
end

user.future_tickets # returns all future tickets for the user
user.tickets        # returns all tickets for the user

Side Note: Also, consider using a more idiomatic datetime column name like ends_at instead of end_date.


You must encapsulate the protected method inside a model method, something like:

class Ticket < ActiveRecord::Base
  def self.all_tickets_from(user)
    with_exclusive_scope{user.tickets.find(:all)}
  end
end
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜