Reputation: 4677
I have a rails app with two models: Schedule and Task. Task belongs_to Schedule and Schedule has_many Tasks. I use a nested form with javascript to allow the user to enter as many tasks as they want when creating a schedule. Here is my form:
<%= form_for [@project, @schedule] do |f| %>
<%= f.fields_for :tasks do |builder| %>
<%= render 'task_fields', :f => builder %>
<% end %>
<p><%= link_to_add_fields "Add task", f, :tasks %>
<p><%= f.submit "Submit" %></p>
<% end %>
And here is the partial the form above refers to:
<p class = "fieldo">
<%= f.label :title %><br />
<%= f.text_field :title %><br />
<%= f.label :content %><br />
<%= f.text_field :content %><br />
<%= f.hidden_field :_destroy %>
<%= link_to_function "remove", "remove_fields(this)" %>
</p>
Here is the schedules controller action for the form:
def new
2.times {@schedule.tasks.build}
end
So, as you can see from the controller, the form will automatically print 2 task forms to the page. Those 3 forms give the following html:
<p class = "fieldo">
<input id="schedule_tasks_attributes_0_title" name="schedule[tasks_attributes][0][title]" type="text" /><br />
<input id="schedule_tasks_attributes_0_content" name="schedule[tasks_attributes][0][content]" type="text" /><br />
</p>
<p class = "fieldo">
<input id="schedule_tasks_attributes_1_title" name="schedule[tasks_attributes][1][title]" type="text" /><br />
<input id="schedule_tasks_attributes_1_content" name="schedule[tasks_attributes][1][content]" type="text" /><br />
</p>
As you can see, the id and name start at 0 and increment by 1. This is good and is how i would expect it to work. The problem is that when i add a task dynamically by pressing the "Add task" button, the id and name become random numbers like this:
<p class = "fieldo">
<input id="schedule_tasks_attributes_1387479041550_title" name="schedule[tasks_attributes][1387479041550][title]" type="text">
<input id="schedule_tasks_attributes_1387479041550_content" name="schedule[tasks_attributes][1387479041550][content]" type="text">
</p>
<p class = "fieldo">
<input id="schedule_tasks_attributes_1387479043642_title" name="schedule[tasks_attributes][1387479043642][title]" type="text">
<input id="schedule_tasks_attributes_1387479043642_content" name="schedule[tasks_attributes][1387479043642][content]" type="text">
</p>
My questions are:
If anyone has seen rails cast #197, this form is based slightly on that. Here is my javascript and a ruby helper I am also using.
javascript:
//Dynamic forms
function remove_fields(link) {
$(link).prev("input[type=hidden]").val("1");
$(link).closest(".fieldo").hide();
}
function add_fields(link, association, content) {
var new_id = new Date().getTime();
var regexp = new RegExp("new_" + association, "g");
$(link).parent().before(content.replace(regexp, new_id));
}
Application helper:
def link_to_add_fields(name, f, association)
new_object = f.object.class.reflect_on_association(association).klass.new
fields = f.fields_for(association, new_object, :child_index => "new_#{association}") do |builder|
render(association.to_s.singularize + "_fields", :f => builder)
end
link_to_function(name, raw("add_fields(this, \"#{association}\", \"#{escape_javascript(fields)}\")"))
end
Upvotes: 3
Views: 1439
Reputation: 54882
1): This huge number comes from the Javascript line var new_id = new Date().getTime();
it sets the HTML id of the new line with a timestamp, which makes it "almost" uniq.
2): Yes you could change this to use a "reasonnable human number".
function add_fields(link, association, content) {
var new_id = Math.floor((Math.random()*10000)+3);
var regexp = new RegExp("new_" + association, "g");
$(link).parent().before(content.replace(regexp, new_id));
}
This would replace the huge number with a random number between 10003 and 3. But I recommend you to let Rails deal with this huge number: First, it discourages the potential evil users of you app, and Second, it is almost-for-sure a uniq id.
But hey, always remember the #1 Developper's rule:
If it ain't broken, don't fix it.
Upvotes: 1
Reputation: 5813
Without seeing more of your code, it's hard to be sure, but I think those are the "temporary" IDs created when you task.build
on the rails side. Use debugger
, pry
, or some puts @schedule.tasks.all.collect{|t| t.id}
to check this.
If that is the case, then no, you can't "get neater numbers", but you wouldn't want to - you just need those to be unique, and for Rails to handle creating the tasks nicely. So, just check to see if your database has what you expect after the create
action, and call it done.
Upvotes: 0