2016-01-20 122 views
2

有没有更好的方法来做下面的代码?Ruby对象质量分配

user.name = "abc" 
user.email = "[email protected]" 
user.mobile = "12312312" 

像这样的东西会做:

user.prepare do |u| 
    u.name = "abc" 
    u.email = "[email protected]" 
    u.mobile = "12312312" 
end 
+2

[DRY方式为对象分配散列值]的可能副本(http://stackoverflow.com/questions/3669801/dry-way-to-assign-hash-values-to-an-object) –

+0

如果'user'是一个'ActiveRecord',那么['attributes ='](http://apidock.com/rails/ActiveRecord/AttributeAssignment/assign_attributes)可能是一个选项。 – spickermann

+0

为什么你喜欢你的第二个例子比第一个更好? – spickermann

回答

0
当你的属性来在哈希的形式

替代选项:

attrs = { 
    name: "abc", 
    email: "[email protected]", 
    mobile: "12312312" 
} 

attrs.each { |key, value| user.send("#{key}=", value) } 
+1

这不会起作用,因为'user.send(key)'会调用getter - 而不是setter方法。你需要做'用户。送( “#{键} =”)'。 – max

+0

感谢您的接收! – fylooi

0

用ActiveRecord对象可以使用.assign_attributes或更新 方法:

user.assign_attributes(name: "abc", email: "[email protected]", mobile: "12312312") 
# attributes= is a shorter alias for assign_attributes 
user.attributes = { name: "abc", email: "[email protected]", mobile: "12312312" } 

# this will update the record in the database 
user.update(name: "abc", email: "[email protected]", mobile: "12312312") 

# or with a block 
user.update(name: "abc", mobile: "12312312") do |u| 
    u.email = "#{u.name}@test.com" 
end 

.update接受一个块,而assign_attributes没有。如果你只是简单地分配一个文字值的哈希值 - 比如用户在参数中传递的值,那么就不需要使用一个块。

如果你有,你想与质量分配香料一个普通的老红宝石对象,你可以这样做:

class User 

    attr_accessor :name, :email, :mobile 

    def initialize(params = {}, &block) 
    self.mass_assign(params) if params 
    yield self if block_given? 
    end 

    def assign_attributes(params = {}, &block) 
    self.mass_assign(params) if params 
    yield self if block_given? 
    end 

    def attributes=(params) 
    assign_attributes(params) 
    end 

    private 
    def mass_assign(attrs) 
     attrs.each do |key, value| 
     self.public_send("#{key}=", value) 
     end 
    end 
end 

这将让你做的事:

u = User.new(name: "abc", email: "[email protected]", mobile: "12312312") 
u.attributes = { email: "[email protected]", name: "joe" } 
u.assign_attributes(name: 'bob') do |u| 
    u.email = "#{u.name}@example.com" 
end 

# etc. 
0

你可以做到以下几点以及:

user.instance_eval do 
    @name = "abc" 
    @email = "[email protected]" 
    @mobile = "12312312" 
end 

您可以访问内部的实例变量user块给instance_eval


,如果你想调用存取方法,而不是直接操作实例变量你可以使用下面的代码。

user.instance_eval do 
    self.name = "xyz" 
    self.email = "[email protected]" 
    self.mobile = "12312312" 
end 

user.instance_eval do |o| 
    o.name = "xyz" 
    o.email = "[email protected]" 
    o.mobile = "12312312" 
end 
+0

我不会推荐这个,因为'instance_eval'打破了封装规则。按照推荐使用'.tap'或'.send'更好。 – max

+0

@max'send'也破坏了封装;-) Ruby的封装仅适用于行为良好的程序员。 –

+0

你就在那里。 'public_send'尽管。有人可能希望'.send'做到了。 – max

0

假设“用户”是你控制的一类,那么你可以定义做你想要的东西的方法。例如:

def set_all(hash) 
    @name, @email, @mobile = hash[:name], hash[:email], hash[:mobile] 
end 

然后在你的代码的其余部分:

user.set_all(name: "abc", email: "[email protected]", mobile: "12312312") 

如果“用户”是的,比方说,一个ActiveRecord模型的实例,然后我就有点动摇你如何得到这个工作的细节。但校长仍然适用:通过将复杂性的责任移交给接收者来干代码。