I have a List model. Lists have embedded Tags (using Mongoid). When a user creates a list, he can specify associated tags via comma separated list in a text field.
How do I store the tags through the List association? Can I do it with accepts_nested_attributes_for :tags on the List model or do I have to pre-process the tags string?
Here’s what I have so far. How do I deal with the tags string, splitting it and storing each tag individually in the embedded tag doc that’s part of list?
List controller:
class ListsController < ApplicationController
def new
@list = List.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: @list }
end
end
def create
list_params = params[:list]
list_params[:user_id] = current_user.id
@list = List.new(list_params)
if @list.save
redirect_to @list, notice: 'List was successfully created.'
else
render action: "new"
end
end
end
List creation form
= form_for @list do |f|
- if @list.errors.any?
#error_explanation
%h2= "#{pluralize(@list.errors.count, "error")} prohibited this list from being saved:"
%ul
- @list.errors.full_messages.each do |msg|
%li= msg
.field
= f.label :name
= f.text_field :name
.field
= f.label :description
= f.text_field :description
.field
= f.fields_for :tags do |t|
= t.label :tags
= t.text_field :name
.actions
= f.submit 'Save'
List model
class List
include Mongoid::Document
include Mongoid::Timestamps
field :name
field :description
embeds_many :items
embeds_many :comments
embeds_many :tags
belongs_to :user
accepts_nested_attributes_for :tags
Tag model
class Tag
include Mongoid::Document
field :name
has_one :list
end
Edit based on Geoff’s suggestion
List controller ultimately looked.
def create
tags = params[:tags][:name]
list = params[:list]
list[:user_id] = current_user.id
@list = List.new(list)
tags.gsub("\s","").split(",").each do |tag_name|
@list.tags.new(:name => tag_name)
end
if @list.save
redirect_to @list, notice: 'List was successfully created.'
else
render action: "new"
end
end
If I understand you correctly, here’s what I think you want to do:
Your view as it is will display a tag name field for each tag, but there are no associated tags at create time so I assume it just doesn’t show anything.
When using a
:has_many, there is a nice little function that will be created for you by rails calledList.tag_ids. Since I am not familiar with it, I am assuming the functionality of:embeds_manyis a superset of of:has_many. The point of this is that if you can provide some sort of form which gathers the ids, then you’d be done. A set of checkboxes could work, or a multi-select. Here is what checkboxes might look like:I asked something similar here:
Rails: How do I transactionally add a has_many association to an existing model?
However, this isn’t what you asked for. You could achieve a form which associates tags by name by using javascript. That would probably be nice, but it would be a bit tricky.
Assuming no javascript, if you are inputting the names as a comma separated list in the view, you will need to parse it in the controller. Similar to this:
View:
Controller:
None of the solutions I suggested make use of nested attributes. I don’t think they are applicable for you here. They are used when you are trying to update the attributes of the nested model, but you’re just trying to make the association.
I hope that helps.