2010-12-07 40 views
7

在我的導軌應用程序中,我有一個帶有start_date和end_date的模型。如果用戶選擇2010年1月1日作爲start_date,並選擇2010年1月5日作爲end_date,則需要創建5個創建模型的實例(每個選定一個日期)。所以它看起來像如何覆蓋導軌模型的「新」方法

Jan 1, 2010 
Jan 2, 2010 
Jan 3, 2010 
Jan 4, 2010 
Jan 5, 2010 

我知道處理這個問題的一種方法是在控制器中做一個循環。像...

# ...inside controller 
start_date.upto(end_date) { my_model.new(params[:my_model]) } 

但是,我想保持我的控制器瘦,再加上我想保持它的模型邏輯。我猜我需要重寫模型中的「新」方法。什麼是最好的方法來做到這一點?

+0

你爲什麼想要? – Chowlett 2010-12-07 13:48:39

+0

我有一個用戶填寫的表單來創建模型。但是這種形式只是一個框架來填補我的模型的細節。該表格具有「開始」和「結束」點等詳細信息。要創建一個完整的模型,需要填入開始點和結束點。我可以在控制器中執行此操作,但我認爲這種類型的邏輯應該放在模型中。 – Lan 2010-12-07 13:54:43

回答

16

由於@brad說,你絕對不想重寫初始化。雖然你可以覆蓋after_initialize,但這看起來並不像你想要的。相反,你可能想要像@Pasta所建議的那樣向類中添加工廠方法。因此,添加到您的模型:

def self.build_for_range(start_date, end_date, attributes={}) 
    start_date.upto(end_date).map { new(attributes) } 
end 

然後添加到您的控制器:

models = MyModel.build_for_range(start_date, end_date, params[:my_model]) 
if models.all?(:valid?) 
    models.each(&:save) 
    # redirect the user somewhere ... 
end 
2

你爲什麼不只是創建一個方法到你的模型像這樣

def self.create_dates(params) 
    [...] 
    end 

含有這種邏輯(基本上是你的循環?)

+0

我想在模型中使用它,因爲這就是創建自身的邏輯應該是的地方,不是嗎?我的模型只需要一個開始和結束日期,然後就可以創建自己的「實例」。 (實例恰好是數據庫表中的多行) – Lan 2010-12-07 13:30:38

+0

所以我會盡我所說在我的答案。一個create_dates類方法,你的循環調用新的內部。 – Pasta 2010-12-07 13:37:05

+0

對不起,我需要更好地說出我的問題。但基本上,我只是想知道如何覆蓋MyModel.new(屬性) – Lan 2010-12-07 13:42:06

2

我猜你想爲你的模型屬性設置默認值?

還有另一種解決方案,而不是重寫;您可以設置回調:

class Model 

before_create :default_values 
def default_values 
    ... 
end 
2

您可以使用:

def initialize(attributes = nil) 
    # do your stuff... 
end 

雖然地方我讀它是不建議...

10

不要覆蓋initialize它可能打破了很多的東西在你的模型中。如果我們知道爲什麼你需要我們可以更好地幫助(不完全理解你的表單是一個框架的解釋,你需要表單屬性來創建其他屬性,見下文)。 Marcel建議我經常使用鉤子。但是,如果您希望它始終發生,不僅在創建或保存對象之前,請使用掛鉤。

def after_initialize 
    # Gets called right after Model.new 
    # Do some stuff here 
end 

此外,如果你只是尋找一些默認值就可以提供默認的訪問器,是這樣的:(其中some_attribute相當於你的模型屬性的列名)

def some_attribute 
    attributes[:some_attribute] || "Some Default Value" 
end 

或作家

def some_attribute=(something) 
    attributes[:some_attribute] = something.with_some_changes 
end 

如果我正確理解您的評論,它看起來像你公開的形式,將使您的模型不完整的,與基於其他屬性在這種形式的部分?在這種情況下,您可以使用上述方法after_initializesome_attribute=中的任何一種在您的模型上創建其他屬性。

2

這種工廠方法patttern的怪胎......找到它。

如果由於某種原因不願意使用每個@Pasta的create_date,那麼可能創建一個簡單的ruby對象(不支持ActiveRecord),名爲YourModelFactory/Template/Whatever with two instance vars - 您可以使用標準params [:foo]來分配這些參數 - 然後在該類上定義並調用返回實際對象的方法。

你的控制器邏輯現在看起來是這樣的:

mmf = MyModelFactory.new(params[:foo]) 
objs = mmf.create_real_deal_models 

好運。

0

嚴格,雖然晚了,正確的方式在一個模型覆蓋

def initialize(args) 
    # 
    # do whatever, args are passed to super 
    # 
    super 
end