如何在Rails中使named_scope返回一个值而不是一个数组?

sam*_*207 17 ruby activerecord ruby-on-rails find

我想编写一个命名范围来从其id获取记录.

例如,我有一个名为的模型Event,我想模拟Event.find(id)使用以named_scope获得未来的灵活性.

我在我的模型中使用了这段代码:

named_scope :from_id, lambda { |id| {:conditions => ['id= ?', id] } }
Run Code Online (Sandbox Code Playgroud)

我从我的控制器那里叫它Event.from_id(id).但我的问题是它返回一个Event对象数组而不是一个对象.

因此,如果我想得到事件名称,我必须写

event = Event.from_id(id)
event[0].name
Run Code Online (Sandbox Code Playgroud)

而我想要的是

event = Event.from_id(id)
event.name
Run Code Online (Sandbox Code Playgroud)

我在这里做错了吗?

小智 12

在这种情况下,我将创建一个类方法

def self.from_id(id)
  self.find(id).first
end
Run Code Online (Sandbox Code Playgroud)

另一个例子:

class Invoice
  def self.number
    self.find(:first, 
      :select => "max(number) As last, max(number)+1 As next", 
      :conditions => "type = 'SalesOrder'")
  end
end
Run Code Online (Sandbox Code Playgroud)

像这样的方法比named_scope更好.你可以打电话Invoice.number.next,比named_scope回来更好Invoice.number[0].next.


Jim*_*dra 10

正如Damien所提到的,使用自定义范围只是为了通过ID查找是不可取的.但要回答你的问题:

查找记录named_scope将始终返回一个ActiveRecord::NamedScope::Scope对象,其行为类似于数组.如果查询只返回一条记录,则可以使用该first方法直接获取ActiveRecord对象,如下所示:

event = Event.from_id(id).first
event.name # will work as you expect
Run Code Online (Sandbox Code Playgroud)


Dam*_*IEU 5

这里没有必要使用范围.你可以做到Event.find_by_id id.和
之间的区别在于find,如果记录不存在find_by_id,第一个将引发ActiveRecordNotFoundException.第二个将返回零.

编写一个范围以通过它的id获取记录是一个非常糟糕的ID,因为它已经由rails本地提供.