How to override the "new" method for the rail model

In my rails application, I have a model with start_date and end_date. If the user selects January 1, 2010 as start_date and January 5, 2010 as end_date, I want 5 instances of my model to be created (one for each selected day). So it will look like

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

I know that one way to handle this is to loop through the controller. Something like...

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

However, I want my controller to be skinny, plus I want to keep the model logic outside of it. I assume that I need to override the "new" method in the model. What is the best way to do this?

+7
ruby-on-rails
Dec 07 '10 at 13:18
source share
7 answers

As @brad says, you definitely don't want to override initialization. Although you can override after_initialize, it doesn't look like what you want here. Instead, you probably want to add a factory method to the class, as @Pasta suggests. So add this to your model:

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

And then add this to your controller:

 models = MyModel.build_for_range(start_date, end_date, params[:my_model]) if models.all?(:valid?) models.each(&:save) # redirect the user somewhere ... end 
+16
Dec 07 '10 at 17:11
source share

Do not override initialize This can break a lot of things in your models. IF we knew why you needed us to be able to help better (do not fully understand your explanation of the form, which is the skeleton, you want the attributes of the form to create other attributes, see below). I often use a hook, as Marcel suggested. But if you want this to happen all the time, and not just before creating or saving an object, use the after_initialize hook.

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

Also, if you are just looking for some default values, you can provide default access devices, for example: (where some_attribute matches the column name of your model attribute)

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

or writer

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

If I understand your comment correctly, it looks like you are revealing a form that will make your model incomplete, and other attributes based on parts of this form? In this case, you can use any of the above methods after_initialize or some_attribute= to then create other attributes in your model.

+10
Dec 07 2018-10-14T00:
source share

why don't you just create a method in your model like this

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

containing this logic (basically your loop?)

+2
Dec 07 '10 at 13:25
source share

I think you want to set default values ​​for your model attribute?

There is another solution than redefinition; you can set callbacks:

 class Model before_create :default_values def default_values ... end 
+2
Dec 07 '10 at 13:55 on
source share

You can use:

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

Although I read somewhere, this was not recommended ...

+2
Dec 07 2018-10-14T00:
source share

It smells like a factory patttern method ... look for it.

If for some reason you do not want to go with create_date for @Pasta, then maybe just create a simple ruby ​​object (not supported by ActiveRecord) called YourModelFactory / Template / Whatever with two instances of vars - you can use your standard options [: foo] to assign them - then define and call a method for this class that returns your real objects.

Now your controller logic looks something like this:

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

Good luck.

+2
Dec 07 '10 at 15:28
source share

Strictly, although late, the correct way to override a new model

 def initialize(args) # # do whatever, args are passed to super # super end 
0
Sep 19 '17 at 2:37 on
source share



All Articles