Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails create form for model with many to many relation

I have two models, Recipe and Tag, with a has_and_belongs_to_many relation. For this relation I have a simple join table, RecipesTags.

Recipe:

has_and_belongs_to_many :tags

Tag:

has_and_belongs_to_many :recipes

Now upon creating a new recipe, the user gets to fill in which category the recipe belongs to in forms of checkboxes, like "Meat", "Fish", and so on. These categories are in fact just tags in the database.

Problem: the recipes doesn't get any tags saved to it.

Recipe new and create controller methods:

    def new
    @recipe = Recipe.new
    @ingredients = Ingredient.all
    @tags = Tag.all

    respond_to do |format|
      format.html # new.html.erb
      format.json { render json: @recipe }
    end
  end



  # POST /recipes
  # POST /recipes.json
  def create
    @recipe = Recipe.new(params[:recipe])
    if (params[:tags])
      @recipe.tags << params[:tags]
    end

    respond_to do |format|
      if @recipe.save
        format.html { redirect_to @recipe, notice: 'Recipe was successfully created.' }
        format.json { render json: @recipe, status: :created, location: @recipe }
      else
        format.html { render action: "new" }
        format.json { render json: @recipe.errors, status: :unprocessable_entity }
      end
    end
  end

The view:

<%= form_for(@recipe, :html => {:multipart => true}) do |f| %>
  <% if @recipe.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@recipe.errors.count, "error") %> prohibited this recipe from being saved:</h2>

# [ fields that get's saved for the recipe and works fine ]

<% @tags.each do |t| %>
      <%= f.label t.name  %>
      <%= f.check_box :tags, t.name  %>
      <br />
    <% end %>

<%= f.submit 'Submit recipe', :class => 'btn btn-primary' %>

<% end %>

At the moment, I get an error message saying: undefined method `merge' for "Meat":String

"Meat" is the tag name.

So, what am I doing wrong here?

like image 483
Majoren Avatar asked Oct 04 '22 20:10

Majoren


2 Answers

I think the issue is this line @recipe.tags << params[:tags]. The association method you're calling with << takes an object (in this case expecting a tag object), but in this case it seems you might be passing it a string.

For more info this link may be helpful http://guides.rubyonrails.org/association_basics.html#has_and_belongs_to_many-association-reference, in particular where it refers to collection<<(object, …).


In your controller you'll want to do something like @recipe.tags << tag where tag is a specific tag object.

So, try this:

In your controller

params[:tags].each do |k,v|
   @recipe.tags << Tag.find(k)
end

In your view

<% @tags.each do |t| %>
  <%= f.label t.name  %>
  <%= f.check_box "tags[#{t.id}]"  %>
  <br />
<% end %>
like image 194
michaelrshannon Avatar answered Oct 13 '22 10:10

michaelrshannon


Try this:

  def create
    @recipe = Recipe.new(params[:recipe])
    params[:tags].each do |tag|
      @recipe.tags << Tag.find_by_name(tag)
    end

    respond_to do |format|
      if @recipe.save
        format.html { redirect_to @recipe, notice: 'Recipe was successfully created.' }
        format.json { render json: @recipe, status: :created, location: @recipe }
      else
        format.html { render action: "new" }
        format.json { render json: @recipe.errors, status: :unprocessable_entity }
      end
    end
  end

In view:

<% @tags.each do |t| %>
  <%= label_tag t.name  %>
  <%= check_box_tag "tags[#{t.name}]", t.name  %>
  <br />
<% end %>
like image 33
Rahul Tapali Avatar answered Oct 13 '22 10:10

Rahul Tapali