4

I have a model, for example :

class Account < ActiveRecord::Base

  before_create :build_dependencies

  def build_dependencies
    # use nifty params to build this related object
    build_nifty_object(params)
  end

The initial params are sent in through a hidden form tag on the Account#new form.

But there's no reason/need for these params to be saved to the account model. I just need them in the NiftyObject model.

Is there a clever way to pass these params to the before_create method ? Or any other alternatives that might accomplish the same task?

Thanks!

Trip
  • 26,756
  • 46
  • 158
  • 277
  • The param hash is normally used in the controller to create your model object. How is niftyObject related to your Account Model? In your code example, we cannot see a belong_to or something indicating you have a relation between theses two objects? – Cygnusx1 Jun 27 '12 at 15:06

3 Answers3

3

You can use instance variables to workaround this, and do +1 step from the controller:

class Account < ActiveRecord::Base

  before_create :build_dependencies

  def assign_params_from_controller(params)
    @params = params
  end

  def build_dependencies
    # use nifty params to build this related object
    build_nifty_object(@params)
  end

In the controller:

  def Create
    account = new Account(params)
    account.assign_params_from_controller( ... )
    account.save   # this will trigger before_create
  end
Matzi
  • 13,770
  • 4
  • 33
  • 50
  • Hmm.. question: how would I apply `assign_params_from_controller(params)` ? – Trip Jun 27 '12 at 15:16
  • 1
    In your controller, you call this before saving the Account instance. – Matzi Jun 27 '12 at 15:22
  • I just realized this wouldn't work because methods in the model are only available for specific objects. Since this would be before_create, I can't think of a way to make it global. – Trip Jun 27 '12 at 16:06
  • `Before_create` is running when you first *save* the model, not when you create it with a new. Check the example. Description: http://railstalk.com/?p=39 – Matzi Jun 27 '12 at 17:04
  • This would never work though : `Account.assign_params_from_controller(params)`. It would have to be : `Account.find(x).assign_params_from_controller(params)` . But since its before_create, I have nothing to choose. – Trip Jun 27 '12 at 18:27
  • 1
    Look the example again. First step, an account is created. Second step, the function is called on this instant. Third step, it is saved, which triggers the before_create. As you can see, the lower case `account` is an instantiated object, not the Account class. With the class, it wouldn't work, but with the newly kcreated object it will work. – Matzi Jun 27 '12 at 19:36
  • Ahhhhh genius! How did I miss that! Thanks! – Trip Jun 27 '12 at 19:44
2

I believe the active-record callback cycle hurts you in most cases, this included. Instead of using before_create, I recommend you use a service object that coordinates the creation of Account and nifty-object.

I assume you want nifty-object to know about the account, so I passed it in to it's create method.

class CreatesAccount
  def self.create(params)
    account = Account.new(params)
    return account unless account.valid?
    ActiveRecord::Base.transaction do
      account.save!
      NifyObject.create(params, account: account)
      return account
    end
  end
end
Jesse Wolgamott
  • 40,197
  • 4
  • 83
  • 109
2

I appreciate everyone's answers. But I finally am going with an attr_accessor instead. In this way, it doesn't save anything anywhere, but would still be accessible from the model in a before_create method.

Trip
  • 26,756
  • 46
  • 158
  • 277