1
votes

I am trying to provide a way to generate a new object ("List") in one model with a new associated object in another ("Item") using a has_many through relationship (through "Groupings"). I was able to get the form working fine but can't figure out what I'm missing in order to finish the creation process correctly.

Rails v. 5.1.2, Ruby v. 2.4.1

lists_controller.rb

    def new
    @list = current_user.lists.new
     3.times { @list.items.build }
    end

    def create
    @list = current_user.lists.new(list_params)
    respond_to do |format|
    if @list.save
    format.html { redirect_to @list, notice: 'List was successfully created.' }
    format.json { render :show, status: :created, location: @list }
    else
    format.html { render :new }
    format.json { render json: @list.errors, status: :unprocessable_entity }
    end
   end
  end

  private
  def set_list
   @list = List.find(params[:id])
  end

 def correct_user
  @list = current_user.lists.find_by(id: params[:id])
  redirect_to lists_path, notice: "Not authorized to edit this list" 
 if @list.nil?
 end


def list_params
  params.require(:list).permit(:title, {
    item_attributes: [
             :id, :title, :url
          ]})
end

items_controller.rb

     def new
       @item = Item.new
     end

    private

     def set_item
      @item = Item.find(params[:id])
     end


    def item_params
       params.require(:item).permit(:title, :body, :url, :created, 
     :list_ids => [])
      end
     end

list.rb model

 has_many :groupings, :dependent => :destroy 
 has_many :items, :through => :groupings

 accepts_nested_attributes_for :items,

 reject_if: ->(attrs) { attrs['title'].blank? || attrs['url'].blank? }

item.rb model

 has_many :groupings, :dependent => :destroy
 has_many :lists, :through => :groupings
 validate :has_lists?
  accepts_nested_attributes_for :lists

 attr_writer :list_titles
 after_save :assign_lists

  def list_titles
   @list_titles || lists.map(&:title).join(' ')
  end
   private

  def assign_lists
    if @list_titles
  self.lists = @list_titles.split(/\,/).map do |title|
    if title[0..0]==" "
      title=title.strip
    end
    title=title.downcase
    List.find_or_create_by_title(title)
   end
  end
 end

  def has_lists?
     errors.add(:base, 'This item needs to be assigned to a list before it can be saved.') if self.lists.blank?
   end

grouping.rb model

 belongs_to :item
 belongs_to :list

 accepts_nested_attributes_for :item, :list

Lists Form

 <%= form_with(model: list,  local: true) do |f| %>
<% if list.errors.any? %>
<div id="error_explanation">
  <h2><%= pluralize(list.errors.count, "error") %> prohibited this list from being saved:</h2>

  <ul>
  <% list.errors.full_messages.each do |message| %>
    <li><%= message %></li>
  <% end %>
  </ul>
</div>
<% end %>

<div class="field">
<%= f.label :title %>
<%= f.text_field :title, id: :list_title %>
</div>

<div>
<p><strong>Items:</strong></p>

 <%= f.fields_for :items do |item| %>
  <div>
    <%= item.label :title %>
    <%= item.text_field :title %>

    <%= item.label :url %>
    <%= item.text_field :url %>
  </div>
 <% end %>
 </div>




 <div class="actions">
<%= f.submit %>
 </div>
 <% end %>

Sample Console Output

Started POST "/lists" for 127.0.0.1 at 2017-09-19 13:12:53 -0700 Processing by ListsController#create as HTML Parameters: {"utf8"=>"✓", "authenticity_token"=>"Y6rszWVUXDIVymuoBkXwvkw1pVbyC6mffiWIZzr7PVd1NT9JJi6rD72k5Fh2qU5Q5tEd0qn6bFYMSJnz2TgjAA==", "list"=>{"title"=>"Websites", "items_attributes"=>{"0"=>{"title"=>"Google", "url"=>"www.google.com"}, "1"=>{"title"=>"Yahoo", "url"=>"www.yahoo.com"}, "2"=>{"title"=>"Bing", "url"=>"www.bing.com"}}}, "commit"=>"Create List"} User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 2], ["LIMIT", 1]] Unpermitted parameter: :items_attributes (0.1ms) BEGIN SQL (0.9ms) INSERT INTO "lists" ("title", "created_at", "updated_at", "user_id") VALUES ($1, $2, $3, $4) RETURNING "id" [["title", "Websites"], ["created_at", "2017-09-19 20:12:53.458577"], ["updated_at", "2017-09-19 20:12:53.458577"], ["user_id", 2]] (0.3ms) COMMIT Redirected to http://localhost:3000/lists/24 Completed 302 Found in 7ms (ActiveRecord: 1.6ms)

I'm still learning, clearly - but after trying all kinds of related hints on this forum I couldn't figure this one out. Thanks for any help!

2

2 Answers

1
votes

You have some mistakes in your syntax when you define your params. It should be like this: (items instead item and you don't need {})

def list_params
  params.require(:list).permit(:title,
  items_attributes: [:id, :title, :url])
end
1
votes

You're almost there but there is an error being reported in your console logs: Unpermitted parameter: :items_attributes.

Change item_attributes to items_attributes in your list_params:

def list_params
  params.require(:list)
        .permit(:title, items_attributes: [:id, :title, :url])
end