malcoauri
malcoauri

Reputation: 12189

Creating 2 objects with has_one association in Rails

I need to get some info about creating new objects in Rails with validation. For example, there is the following code:

def create
  @user = User.new(params[:user])
  if @user.save
    # some actions: redirect, render, etc
  else
    render 'new'
  end
end

But if there is 2 models with has_one association, for example Club and Place. I need to create both this objects from params in the same 'create' action, because I've got the same form for inputing data for it(params[:club] and params[:club][:place]). I don't know how I should save this objects, because for building a place (@club.build_place(params[:club][:place])) I should save @club in database. Please, give me example of the code for my problem. Thanks in advance.

Upvotes: 2

Views: 144

Answers (1)

Helios de Guerra
Helios de Guerra

Reputation: 3475

If you're creating multiple objects from a single form you'd probably be best off putting this logic into a "Form Object"... See the article "7 Patterns to Refactor Fat ActiveRecord Models" from the CodeClimate blog found here (look for Section #3 on extracting Form Objects): http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models.

Railscasts also has a good episode on form objects, though it is a "Pro Episode" (i.e. requires subscription). http://railscasts.com/episodes/416-form-objects

In short, you create a custom model including some of the necessary ActiveModel modules then create a custom save method, e.g. (this is directly from the article which has a lot of great advice).

class Signup
  include Virtus

  extend ActiveModel::Naming
  include ActiveModel::Conversion
  include ActiveModel::Validations

  attr_reader :user
  attr_reader :company

  attribute :name, String
  attribute :company_name, String
  attribute :email, String

  validates :email, presence: true
  # … more validations …

  # Forms are never themselves persisted
  def persisted?
    false
  end

  def save
    if valid?
      persist!
      true
    else
      false
    end
  end

private

  def persist!
    @company = Company.create!(name: company_name)
    @user = @company.users.create!(name: name, email: email)
  end
end

This gives you much more control and a much cleaner interface.

Upvotes: 3

Related Questions