malcoauri
malcoauri

Reputation: 12189

Build association with accepts_nested_attributes using some condition in Rails 4

I have got the following task to do:

There is 2 models: Order and User, and there is form for building a new order. This form must contains fields for building User association - name, phone. I have got no problems with it; I should just use accept_nested_attributes in Order model and build Order with nested User, it's ok. But if User with the same phone exists already I want just user_id for a new Order be installed as user_id of existed User without creating a new User. How can I do it better? I don't know how to build association using some condition. Thanks in advance.

Upvotes: 0

Views: 68

Answers (2)

Mandeep
Mandeep

Reputation: 9173

Inside your create action of orders_controller.rb you could do something like this

def create
  @user = User.find(params[:phone_number])
  if @user
    @order = @user.build_orders(order_params_without_user)
    if @order.save
      redirect_to your_path
    else
      render new
    end
  else
    @order = Order.new(order_params_with_user)
    if @order.save
      redirect_to your_path
    else
      render new
    end
  end
end

private

def order_params_without_user
  params.require(:order).permit(order attributes)
end

def order_params_with_user
  params.require(:order).permit(order_attributes, user_attributes: [ user_attributes ])
end

You can simplify it even further by separating the @order.save if-else block in a method and then calling that method inside your create action like:

def create
  @user = User.find(params[:phone_number])
  if @user
    @order = @user.build_orders(order_params_without_user)
    order_save(@order)
  else
    @order = Order.new(order_params_with_user)
    order_save(@order)
  end
end

private

def order_params_without_user
  params.require(:order).permit(order attributes)
end

def order_params_with_user
  params.require(:order).permit(order_attributes, user_attributes: [ user_attributes ])
end

def order_save(order)
  if order.save
    redirect_to your_path
  else
    render new
  end
end

If you are using rails 4 you can make two private methods order_params_with_user and order_params_without_user, with permitting user attributes in order_params_with_user and then simply pass them on the if-else blocks.

As you mentioned in your comment how can i use find_or_create, if you are using rails 4 then you'll have to permit your attributes and you'll pass that to your find_or_create method but since you want to permit different attributes in different conditions so it'll be better if you separate them out.

Upvotes: 0

Hass
Hass

Reputation: 1636

@user = User.find_or_create_by(phone_number: params[:phone_number])

This way, you only create the user record if it doesn't exist eliminating duplication.

Upvotes: 1

Related Questions