2015-01-15 64 views
0

今晚与我的一位同事就Rails中的方法vs属性进行了辩论。我发誓我以前见过这个,除非我疯了。下面是一个例子:方法vs属性Rails

我们有一个用户模型,我们希望在保存记录之前确定我们有名字和姓氏。我讨厌回调,但对于这个例子,我们假设它是在before_save回调中。

class User  
    before_save :set_first_last 

    def set_first_last 
    first_name if self.first_name.blank? 
    last_name if self.last_name.blank? 
    end 

    def first_name 
    self.first_name = self.name.split(" ").first 
    end 

    def last_name 
    self.last_name = self.name.split(" ").last 
    end 
end 

所以,我很好奇,如果方法“set_first_last”的名字被调用,它看到用户的属性,如first_name是空白的,它会调用方法“FIRST_NAME”,正确吗?用户的属性first_name与名为“first_name”的方法不同。因此,名为“first_name”的用户对象上的属性与Rails中名为“first_name”的用户类上的方法不同,对吗?这将像一个类级别的方法vs实例方法?只是想确定我是正确的,而且我正确地解释了这一点。

感谢

--Mike

回答

0

要回答我想我明白了部分:是的,在模型的属性值比的方法完全不同。

以用户模型,用户控制器及其相应视图之一为例。让我们假设用户模型本身包含first_namelast_nameemail性质:

class User < ActiveRecord::Base 
    #Ensure presence of the following before saving model 
    validates_presence_of :first_name, :last_name, :email 

    #Verify unique email 
    validates_uniqueness_of :email 

    #Here's our lone User method...poor guy 
    def admin? 
    self.company_members.where('? = ANY (company_members.roles)', Role::ADMIN).any? 
    end 
end 

当你身边与你的控制器模型的实例工作,它会是这个样子:

class UsersController < ApplicationController 
    def index 
    #Let's just grab a random user 
    @user = User.find(1) 
    end 
end 

最后,在你看来,你的属性(属性),可以通过以下方式获得:

####views/users/index.html.haml#### 

.random-class 
    = "You're logged in as #{@user.first_name}!" 

但是我们也可以在视图中调用用户方法。继续关闭我们的最后一个例子,我们可以添加这样的事情:

####views/users/index.html.haml#### 

.random-class 
    = "You're logged in as #{@user.first_name}!" 
    - if @user.admin? 
    = 'Oh my gosh, our freaking User method worked!' 

因此,在短期,你在正确的属性和方法有很大的不同,虽然他们看时间差不多。

最后,值得指出的是实例方法只是:方法叫上实例的类的,而类方法被称为一个实际的模型对象,而不是模型对象的单一实例。 Here's a great link to learn more about the differences.

希望这有助于!

+0

当您执行'@ user.first_name'时,您肯定会调用名为'first_name'的方法(然后调用read_attribute) –

+0

您是绝对正确的,Frederick。尽管如此,我还是试图将此归咎于语言学,而不必解释发生的整个过程。我认为迈克只是在寻找快速验证。不过谢谢您的进一步澄清。 –

0

是的,你解释的是正确的。 你的编码将会工作,并为分隔的表格指定姓氏名字&。 进一步,你可以写这样的代码,以及(假设你的全名由用空格隔开,2个字)

#user.rb 
class user  
    before_save :assign_individual_names 

private 
    def assign_individual_names 
    first_name, last_name = name.split(' ') 
    end 

end 
1

我想你是误读该位代码:

def set_first_last 
    first_name if self.first_name.blank? 
    last_name if self.last_name.blank? 
end 

该代码调用first_name方法,如果为空,则再次调用first_name方法(换句话说,该方法的if部分是毫无意义的)

这种代码的构造方式,永远不会使用first_name和last_name属性的值(除非你在查询中使用它们) - 只要你做了user.first_name它就会从name重建它。一个更常见的模式是设置名称的方法,如ensure_first_name(基本上任何不和getter一起使用的类)

实例变量(例如@foo)与具有相同名称的方法不同,虽然foofoo=当然是获取/设置该名称的实例变量的方法。也许你在想这个?在某个事件中,Activerecord模型的属性不存储在单独的实例变量中。