koanima
koanima

Reputation: 577

How to create an object associated with a user in Rails 4 using nested resources?

Using Rails 4, I'm trying to create an object using form_for and have it associated correctly with the user. I nested the "menu" resource under "user", because a menu belongs_to a user, and a user has_many menus. When the user submits the new menu form, I want the menu to save and for it to be associated with the user.

How would you do that? The below code works, because in the create method of the controller I explicitly shovel the new menu into the current_user.menus, but it feels like a work around. I've been searching for an answer, but haven't been able to find a real good example.

Thanks for any help. Also, this is my first StackOverflow question, so also please feel free to suggest how to improve.

The routes look like this:

  resources :users do
    resources :menus, shallow: true   
  end

The controller looks like this:

  def new
    @menu = Menu.new
  end

  def create
    @menu = Menu.new(menu_params)
    current_user.menus << @menu

    if @menu.save
      flash[:notice] = "Menu saved"
    else
      flash[:notice] = "Sorry, menu did not save. Please try again."
    end

    redirect_to user_menus_url
  end

  private

  def menu_params
    params.require(:menu).permit(:name)
  end

The form on the view looks like this:

<%= form_for @menu, url: user_menus_path(current_user), html: {method: "post", class: "menu_form"} do |f| %>
  <%= f.text_field :name %>
  ...
  <%= f.submit "Create" %>
<% end %>

Upvotes: 3

Views: 734

Answers (2)

koanima
koanima

Reputation: 577

This form sends the parameters as such: {"menu"=>{"name"=>"salads"}, "user_id"=>"1"}

These seem to be the two best options for automatically building the new object (menu) with the parent object (user) properly recorded:

Option 1, Building with the association:

  def create
    user = User.find(params[:user_id])
    @menu = user.menus.new(menu_params)

    #....rest of the method...
  end

Option 2, using the .where, as mwoods79 shows:

  def create
    @menu = Menu.where(user_id: params[:user_id]).new(menu_params)

    #....rest of the method...
  end

Upvotes: 0

mwoods79
mwoods79

Reputation: 1648

Does you prefer this style?

def create
  flash[:notice] = menu.valid? ? "Menu saved" : "Sorry, menu did not save. Please try again."

  redirect_to user_menus_url
end

private

def menu_params
  params.require(:menu).permit(:name)
end

# this is where the magic happens
def menu
  Menu.where(user_id: current_user.id).create(menu_params)
end

Upvotes: 1

Related Questions