2016-01-20 172 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模型的實例,然後我就有點動搖你如何得到這個工作的細節。但校長仍然適用:通過將複雜性的責任移交給接收者來幹代碼。