Adding Forms Dynamically From Dropdown Menu Selection - javascript

I have a Ruby on Rails question about adding a dynamic form through a drop down selection rather than having individual buttons for each possible selection.
Right now, through the help of following some Railscasts, my application works where I have three individual buttons that are able to dynamically add three different types of nested forms to the parent, all corresponding to different models with different form partials.
The parent model here is a Workout, allowing traditional_blocks, emon_blocks, and tempo_blocks to be added dynamically using JS.
Workout Model
class Workout < ActiveRecord::Base
has_many :tempos
has_many :traditionals
has_many :emons
accepts_nested_attributes_for :tempos, allow_destroy: true
accepts_nested_attributes_for :emons, allow_destroy: true
accepts_nested_attributes_for :traditionals, allow_destroy: true
end
/app/views/workouts/new.html.erb
<div>
<%= button_to_add_fields "Add EMON Block", f, :emons %>
<%= button_to_add_fields "Add traditional Block", f, :traditionals %>
<%= button_to_add_fields "Add tempo Block", f, :tempos %>
</div>
/apps/helpers/application_helper.rb
module ApplicationHelper
def button_to_add_fields(name, f, association)
new_object = f.object.send(association).klass.new
id = new_object.object_id
fields = f.fields_for(association, new_object, child_index: id) do |builder|
render(association.to_s.singularize + "_fields", f: builder)
end
button_to(name, '#', class: "add_fields", data: {id: id, fields: fields.gsub("\n", "")})
end
end
app/assets/javascripts/workouts.js.coffee
$(document).on 'click', 'form .add_fields', (event) ->
time = new Date().getTime()
regexp = new RegExp($(this).data('id'), 'g')
$(this).before($(this).data('fields').replace(regexp, time))
event.preventDefault()
Like I said earlier, everything works as I want it to when I click the buttons. However, I would like to be able to put "emon block, traditional block, tempo block" inside a collection_select with one button next to the collection_select that says "create." When that "create" button is clicked, I would like it to call that same helper(button_to_add_fields) passing along the necessary parameters for it to work the same way it does now with the multiple button implementation but using the currently selected association in the collection select.
Any tips?

You'll want to use Ajax for this
The Railscast you viewed, although helpful, is somewhat limited in the way that it will only allow you to add a single nested form each time
--
Ajax
#config/routes.rb
resources :workouts do
get "ajax_fields/:type", on: :collection
end
#app/models/workout.rb
Class Workout < ActiveRecord::Base
...
def self.build type
workout = self.new
if type
workout.send(type).build
else
workout.tempos.build
workout.traditionals.build
workout.emons.build
end
end
end
#app/controllers/workouts_controller.rb
Class WorkoutsController < ApplicationController
def ajax_update
#workout = Workout.build params[:type]
render "form", layout: !request.xhr?
end
end
#app/views/workouts/_form.html.erb
<%= form_for #workout do |f| %>
<%= render "fields", locals: { f: f }, onject: params[:type] %>
<%= f.submit %>
<% end %>
#app/views/workouts/_fields.html.erb
<%= f.fields_for type.to_sym, child_index: Time.now.to_i do |t| %>
<%= t.text_field :your_field %>
<% end %>
#app/views/workouts/new.html.erb
<%= form_for #workout do |f| %>
<%= render: "fields", locals: { f: f}, collection: ["tempos", "traditionals", "emons"], as: :type %>
<%= ... dropdown code ...%>
<%= f.submit %>
<% end %>
--
This will allow you to send the following ajax request:
#app/assets/javascripts/workouts.js.coffee
$(document).on 'change', 'form .add_fields', (event) ->
type = $(this).val
$.ajax
url: "/workouts/ajax_fields/" + type,
success: function(data) {
$("form").append(data); // will have to work this out properly
}
});
This should give you the ability to append the extra fields you need to the application, which will then come back with the appropriate HTML for you to append to your DOM
Hopefully you can appreciate the sentiment here - it might not work right out of the box!

Related

Is there a way to regenerate link_to_add_association (specifically data-association-insertion-template)?

Built a very basic rails app to manipulate nested attributes using cocoon and the add and remove links work great. However, it wasn't too long until I wanted to alter the underlying content of what was inserted, say in response to another field changing the list of option values in an included select tag. It appears that the contents to be added are contained in an 'a' tag data element (data-association-insertion-template). I can quite easily change the select options for all included lines via jQuery but changing the behavior of the link_to_add_association is beyond me.
Here are snippets of my example:
_form.html.erb
<div>
<strong>Entries:</strong>
<div id="entries" style="border: thin solid">
<%= f.fields_for :entries do |oi| %>
<%= render "entry_fields", f: oi %>
<% end %>
<div class="links">
<%= link_to_add_association 'Add Entry', f, :entries, {id: 'cocoon-add-entry'} %>
</div>
</div>
</div>
_entry_fields.html.erb
<div class="nested-fields">
<%= f.label :item_id %>
<%= f.select :item_id, #items.collect {|i| [i.style, i.id]}, {include_blank: true}, {selected: :item_id, multiple: false} %>
<%= f.label :decoration_id, 'Decoration' %>
<%= f.select :decoration_id, #decorations.collect { |d| [ d.name, d.id ] }, {include_blank: true}, {selected: :decoration_id, multiple: false, class: 'decoration'} %>
<%= f.label :color %>
<%= f.text_field :color %>
<%= f.label :size_id %>
<%= f.select :size_id, #sizes.collect { |s| [ s.name, s.id ] }, {include_blank: true}, {selected: :size_id, multiple: false} %>
<%= f.label :number %>
<%= f.number_field :number, value: 1, min: 1 %>
<%= f.check_box :_destroy, hidden: true %>
<%= link_to_remove_association "Remove Entry", f %>
</div>
orders.coffee
ready = ->
$('.customer').change ->
$.ajax
url: '/orders/change_customer'
data: { customer_id : #value }
$(document).ready(ready)
$(document).on('turbolinks:load', ready)
order_controller.rb
def change_customer
#decorations = Decoration.joins(:logo).where('logos.customer_id = ?', params[:customer_id])
respond_to do |format|
format.js
end
end
change_customer.js.erb
// update all existing entry decorations with new customer driven options
<% new_decor = options_from_collection_for_select(#decorations, :id, :name) %>
var new_decor_options = "<option value='' selected='selected'></option>" + "<%=j new_decor %>";
$('.decoration').html(new_decor_options);
// now need to change $('#cocoon-add-entry').attr('data-association-insertion-template, ???);
// or regenerate link entirely - but don't have required data to do so here (form builder from original)
I have tried to manipulate the template data string directly via js str.replace but that is one ugly regular expression because of the unescapeHTML and htmlsafe operations done to make it an attribute in the first place. And, that approach doesn't smell good to me. I have been slowly working through the cocoon view_helpers and javascript but nothing seems to fit or I don't seem to have the right methods/data values to build a replacement link. Suggestions?
BTW, kudos for cocoon gem.
After a lot of gnashing of teeth, I have cobbled together a potential solution. I haven't decided if I will let this go into production yet because of the limitations but thanks to combining several different SO questions and answers, the following works:
change_customer.js.erb
// update all existing entry decorations with new customer driven options
<% new_decor = options_from_collection_for_select(#decorations, :id, :name) %>
var new_decor_options = "<option value='' selected='selected'></option>" + "<%=j new_decor %>";
$('.decoration').html(new_decor_options);
// update the Add Entry link to capture new decorations set.
// Note use of ugly hack to recreate 'similar' form.
// Also note that this will only work for new order; will have to revise for edit.
'<%= form_for(Order.new) do |ff| %>'
$('#cocoon-add-entry').replaceWith("<%=j render partial: 'add_entry_link', locals: {f: ff} %>");
'<% end %>'
_add_entry_link.html.erb
<%= link_to_add_association 'Add Entry', f, :entries, {id: 'cocoon-add-entry', data: {'association-insertion-method' => 'after'}} %>

Issues with nested forms

I'm trying to create a fully manageable website where the user can fill some skills ('css', 'php', 'ruby', you name it). Next to it, they fill how good they think they are with this, in a percentage.
I intend to display the result in graphs but right now I'm stuck with this nested form, I can't make them show up.
So as I said earlier, you can add your skills in a page named settings, so here is how I linked them together:
skill.rb and setting.rb
class Skill < ApplicationRecord
belongs_to :settings, optional: true
end
class Setting < ApplicationRecord
has_many :skills, dependent: :destroy
accepts_nested_attributes_for :skills, allow_destroy: true,
reject_if: proc { |att| att['name'].blank? }
# Other lines...
ApplicationHelper.rb
def link_to_add_row(name, f, association, **args)
new_object = f.object.send(association).klass.new
id = new_object.object_id
fields = f.fields_for(association, new_object, child_index: id) do |builder|
render(association.to_s.singularize, f: builder)
end
link_to name, '#', class: 'add_fields' + args[:class], data: { id: id, fields: fields.gsub('\n', '') }
end
application.js
$(document).on('turbolinks:load', function() {
$('form').on('click', '.remove_skill', function(event) {
$(this).prev('input[type="hidden"]').val('1');
$(this).closest('div').hide();
return event.preventDefault();
});
$('form').on('click', '.add_fields', function(event) {
let regexp, time;
time = new Date().getTime();
regexp = new RegExp($(this).data('id'), 'g');
$('.skills').append($(this).data('skills').replace(regexp, time));
return event.preventDefault();
});
});
views/settings/_form.html.erb
<!-- Some other fields -->
<table>
<thead>
<tr>
<th></th>
<th>Compétence</th>
<th>Maîtrise</th>
</tr>
</thead>
<tbody class="fields">
<%= fields_for :skills do |builder| %>
<%= render 'skill', f: builder %>
<% end %>
<%= link_to_add_row('Ajouter skill', f, :skills, class: 'add_skill') %>
</tbody>
</table>
<!-- Some other fields -->
**views/settings/_skill.html.erb
<tr>
<td>
<%= f.input_field :_destroy, as: :hidden %>
<%= link_to 'Delete', '#', class: 'remove_record' %>
</td>
<td><%= f.input :name, label: false %></td>
<td><%= f.input :completed, label: false %></td>
<td><%= f.input :due, label: false, as: :string %></td>
</tr>
I followed this video's instruction, and so far when I click on "add skill", I can see my nested form being rendered in my rails console, but that's all.
I think this is just something I didn't see, but I redid the tutorial twice and each time a bit different but nothing shows when i click on "add skill".
Any help is welcomed!
A few things to look at. first, this function:
$('form').on('click', '.add_fields', function(event) {
let regexp, time;
time = new Date().getTime();
regexp = new RegExp($(this).data('id'), 'g');
$('.skills').append($(this).data('skills').replace(regexp, time));
return event.preventDefault();
});
Is looking for an element with a 'skills' class on it and will append the records there. I didn't see an element with it above unless I missed it.
Next, try disabling turbolinks, at least when debugging - I have had problems with that before.
Remove the gem 'turbolinks' line from your Gemfile.
Remove the //= require turbolinks from your app/assets/javascripts/application.js.
Remove the two "data-turbolinks-track" => true hash key/value pairs from your app/views/layouts/application.html.erb.
(from blog.steveklabnik.com/posts/2013-06-25-removing-turbolinks-from-rails-4
After that, throw in a wad of
console.log()
statements in to verify expected values are what you expect, elements exist etc at runtime.
Finally, I have a post about something similar here:
Javascript nested forms for has_many relationships
Which might be of use.

Save two models (which belong_to a third model) with one submit?

When the user clicks submit how can the info from two different models/DB tables be passed?
The user should be able to create a note in the missed_dates form and then that note should be saved to the respective #challenge the missed date is referring to.
missed_dates/form.html.erb
<%= simple_form_for(#missed_date, url: challenge_missed_dates_path({ routine_id: #challenge }), remote: request.xhr?, html: { data: { modal: true } }) do |a| %>
<%= form_for [#notable, #note] do |b| %>
<%= a.text_field :one %>
<%= b.text_field :two %>
<%= button_tag(type: 'submit') do %>
Save
<% end %>
<% end %>
<% end %>
missed_date.rb
class MissedDate < ActiveRecord::Base
belongs_to :user
belongs_to :challenge
end
missed_date_controller
def new
#challenge = current_user.challenges.find(params[:challenge_id])
#missed_date = current_user.missed_dates.build
#notable = #challenge
#note = Note.new
end
def create
challenge = current_user.challenges.find(params[:challenge_id])
challenge.missed_days = challenge.missed_days + 1
challenge.save
#missed_date = challenge.missed_dates.build(missed_date_params)
#missed_date.user = self.current_user
#missed_date.save
respond_modal_with #missed_date, location: root_path
flash[:alert] = 'Strike added'
end
Short: use "belongs_to" and "has_many :through" association between Note and MissedDates. Then you can use nested attributes.
Long version: This in probably an issue of an improper or incomplete structure of your models. Usually, you can use nested attributes (see http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html) to achieve this.
But, this implies that the models have a direct relation. You should consider if you can do a belongs_to/has_many relation between the note and the missed_date model. This could be done e.g. by "has_many :through..." (http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association) without changing your current db scheme.

Creating Rails 4 Form with Join Table Metadata

Very new Rails 4 developer here. I've got a form where a user is creating Exercises. Exercises can have many Equipment, and Equipment can be optional( think push-up stands for doing push-ups ). I store this "optional" field on the join table exercise_equipment.
I cannot get the parameters to actually send through the values of the collection element that I pick. See below for the model, view, controller, and parameters.
Here are the attributes/relationships of my models:
# id :integer
# name :string
# is_public :boolean
Exercise
has_many :exercise_equipment
has_many :equipment, :through => :exercise_equipment
accepts_nested_attributes_for :exercise_equipment
# id :integer
# exercise_id :integer
# equipment_id :integer
# optional :boolean
ExerciseEquipment
belongs_to :exercise
belongs_to :equipment
accepts_nested_attributes_for :equipment
# id :integer
# name :string
Equipment
has_many :exercise_equipment
has_many :exercises, :through => :exercise_equipment
Here are some (maybe) relevant controller methods:
def new
#exercise = Exercise.new
#exercise.exercise_equipment.build
end
def create
#exercise = Exercise.new( exercise_params )
if #exercise.save
redirect_to #exercises
else
render 'new'
end
end
def edit
#exercise = Exercise.find( params[:id] )
end
def update
#exercise = Exercise.find( params[:id] )
if #exercise.update_attributes( exercise_params )
redirect_to #exercises
else
render 'edit'
end
end
def exercise_params
params.require( :exercise ).permit(
:name,
:is_public,
exercise_equipment_attributes: [
:id,
:optional,
equipment_attributes: [
:id,
:name
],
]
)
end
This is my shot at creating a view to do what I want:
exercises/new.html.erb
<%= form_for #exercise do |f| %>
<%= render 'form', f: f %>
<%= f.submit "New Exercise" %>
<% end %>
exercises/_form.html.erb
<%= f.label :name %><br />
<%= f.text_field :name %>
<%= f.check_box :is_public %> Public
<%= f.fields_for( :exercise_equipment ) do |eef|
<%= eef.fields_for( :equipment ) do |ef|
ef.collection_select :id, Equipment.all, :id, :name %>
<% end %>
<%= eef.check_box :is_optional %> Optional
<% end %>
When I put all of this together and submit an update to an already-existing exercise, the values all go through the params hash, but aren't changed to the new values I've selected...
Parameters: {
"utf8"=>"[checkbox]",
"authenticity_token"=>"[token]",
"exercise"=>{
"name"=>"Test",
"is_public"=>"1",
"exercise_equipment_attributes"=>{
"0"=>{
"equipment_attributes"=>{
"id"=>"1"
},
"optional"=>"1",
"id"=>"2"
}
}
},
"commit"=>"Save Exercise",
"id"=>"1"
}
If you can help me out, I'd be super appreciative. Just let me know if you need any more information and I can provide it.
EDIT
Here is the state of the database before updating:
postgres#=>db=# select id, name, is_public from exercises;
id | name | is_public
----+------+-----------
2 | Test | t
(1 row)
Time: 61.279 ms
postgres#=>db=# select id, exercise_id, equipment_id, optional from exercise_equipment;
id | exercise_id | equipment_id | optional
----+-------------+--------------+----------
2 | 2 | 1 | t
(1 row)
Time: 58.819 ms
postgres#=>db=# select id, name from equipment where id = 1;
id | name
----+-------------
1 | Freeweights
(1 row)
I then go to the update route for that exercise, select a different equipment from the collection, and submit the form. I get the following Rails Console results:
Started PATCH "/exercises/system-test" for 127.0.0.1 at 2014-08-12 23:48:18 -0400
Processing by ExercisesController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"PsbbUPSCiIew2Fd22Swn+K4PmLjwNDCrDdwXf9YBcm8=", "exercise"=>{"name"=>"Test", "is_public"=>"1", "exercise_equipment_attributes"=>{"0"=>{"equipment_attributes"=>{"id"=>"1"}, "optional"=>"1", "id"=>"2"}}}, "commit"=>"Save Exercise", "id"=>"system-test"}
Exercise Load (60.5ms) SELECT "exercises".* FROM "exercises" WHERE "exercises"."slug" = 'system-test' ORDER BY "exercises"."id" ASC LIMIT 1
(57.3ms) BEGIN
ExerciseEquipment Load (76.2ms) SELECT "exercise_equipment".* FROM "exercise_equipment" WHERE "exercise_equipment"."exercise_id" = $1 AND "exercise_equipment"."id" IN (2) [["exercise_id", 2]]
Equipment Load (59.1ms) SELECT "equipment".* FROM "equipment" WHERE "equipment"."id" = $1 LIMIT 1 [["id", 1]]
User Load (60.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 10]]
Exercise Exists (60.5ms) SELECT 1 AS one FROM "exercises" WHERE ("exercises"."name" = 'Test' AND "exercises"."id" != 2 AND "exercises"."user_id" = 10) LIMIT 1
(64.8ms) COMMIT
Redirected to http://localhost:3000/exercises/system-test
Completed 302 Found in 590ms (ActiveRecord: 580.0ms)
Started GET "/exercises/system-test" for 127.0.0.1 at 2014-08-12 23:48:19 -0400
Processing by ExercisesController#show as HTML
Parameters: {"id"=>"system-test"}
Exercise Load (64.1ms) SELECT "exercises".* FROM "exercises" WHERE "exercises"."slug" = 'system-test' ORDER BY "exercises"."id" ASC LIMIT 1
Equipment Load (58.7ms) SELECT "equipment".* FROM "equipment" INNER JOIN "exercise_equipment" ON "equipment"."id" = "exercise_equipment"."equipment_id" WHERE "exercise_equipment"."exercise_id" = $1 [["exercise_id", 2]]
Rendered exercises/show.html.erb within layouts/application (122.7ms)
User Load (60.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = 10 ORDER BY "users"."id" ASC LIMIT 1
Rendered shared/_header.html.erb (61.9ms)
Rendered shared/_alerts.html.erb (0.1ms)
Completed 200 OK in 264ms (Views: 21.3ms | ActiveRecord: 240.8ms)
Firstly, you need to make sure you define your associations correctly.
Any has_many association should be defined with a plural name -
#app/models/exercise.rb
Class Exercise < ActiveRecord::Base
has_many :exercise_equipments
has_many :equipments, :through => :exercise_equipments
accepts_nested_attributes_for :exercise_equipments
end
#app/models/exercise_equipment.rb
Class ExerciseEquipment < ActiveRecord::Base
belongs_to :exercise
belongs_to :equipment
end
#app/models/equipment.rb
Class Equipment < ActiveRecord::Base
has_many :exercise_equipments
has_many :exercises, through: :exercise_equipments
end
If you've already got it working, and are happy with what you've got, then I'd recommend keeping your current setup. However, you may wish to adopt the above for convention's sake
Edit I see from the deleted answer that Beartech investigated this, and turns out Rails treats Equipment / Equipments as the same. Will be worth ignoring the above, but I'll leave it for future reference
Params
I cannot get the parameters to actually send through the values of the
collection element that I pick. See below for the model, view,
controller, and parameters.
I think I get what you mean - you're looking to update the record, but it does not send through the updated parameters to your controller, hence preventing it from being updated.
Although I can't see any glaring problems, I would recommend the issue is that you're trying to populate the exercise_id of an Exercise object. You need to define it for the exercise_equipment object:
<%= f.fields_for :exercise_equipment do |eef| %>
<%= eef.collection_select :equipment_id, Equipment.all, :id, :name %>
<%= eef.check_box :is_optional %>
<% end %>
This will populate your exercise_equipment table as described here:
Time: 61.279 ms
postgres#=>db=# select id, exercise_id, equipment_id, optional from exercise_equipment;
id | exercise_id | equipment_id | optional
----+-------------+--------------+----------
2 | 2 | 1 | t
(1 row)
Currently, you're populating the Equipment model with equipment_id - which won't work. Populating the model in that way will server to create a new record, not update the ones already created
Extra Field
I want to have a link to add an additional equipment field when it is
clicked, similar to how Ryan Bates did it in this RailsCast, but the
helper method he writes( see "Show Notes" tab if you're not subscribed
to see the source ) seems to become substantially more complex when
dealing with the nested views shown in my code below. Any help in
dealing with this?
This a trickier mountain to overcome
Ryan uses quite an outdated method in this process (to pre-populate the link and then just let JS append the field). The "right" way is to build a new object & append the fields_for from ajax. Sounds tough? That's because it is :)
Here's how you do it:
#config/routes.rb
resources :exercises do
collection do
get :ajax_update #-> domain.com/exercises/ajax_update
end
end
#app/models/exercise.rb
Class Exercise < ActiveRecord::Base
def self.build
exercise = self.new
exercise.exercise_equipment.build
end
end
#app/controllers/exercises_controller.rb
Class ExercisesController < ApplicationController
def new
#exercise = Exercise.build
end
def ajax_update
#exercise = Exercise.build
render "add_exercise", layout: false #> renders form with fields_for
end
end
#app/views/exercises/add_exercise.html.erb
<%= form_for #exercise do |f| %>
<%= render partial: "fields_for", locals: { form: f } %>
<% end %>
#app/views/exercises/_fields_for.html.erb
<%= f.fields_for :exercise_equipment, child_index: Time.now.to_i do |eef| %>
<%= eef.collection_select :equipment_id, Equipment.all, :id, :name %>
<%= eef.check_box :is_optional %>
<% end %>
#app/views/exercises/edit.html.erb
<%= form_for #exercise do |f| %>
<%= render partial: "fields_for", locals: { form: f } %>
<%= link_to "Add Field", "#", id: "add_field" %>
<% end %>
#app/assets/javascripts/application.js
$(document).on("click", "#add_field", function() {
$.ajax({
url: "exercises/ajax_update",
success: function(data) {
el_to_add = $(data).html()
$('#your_id').append(el_to_add)
}
});
});

Getting Cloudinary direct uploads to work with a nested model and dynamically added upload fields

I'm trying to get Cloudinary direct uploads working on a Rails app using Carrierwave and accepts_nested_attributes_for to submit one or more images with a post. It works fine until I try to dynamically add more upload fields. For some reason those added dynamically won't start uploading when an image/file is chosen.
Details...
Models summary:
class Post < ActiveRecord::Base
has_many :images
accepts_nested_attributes_for :images,
reject_if: proc { |a| a['file'].blank? && a['file_cache'].blank? }
attr_accessible :images_attributes
end
class Image < ActiveRecord::Base
belongs_to :post
attr_accessible :file, :file_cache
mount_uploader :file, ImageUploader
end
Controller summary:
(A starting point, allowing me to have up to three images with a post)
class PostsController < ApplicationController
def new
#post = Post.new
3.times { #post.images.build }
end
end
Head:
<!DOCTYPE html>
<html>
<head>
...
<%= javascript_include_tag "application" %>
<%= cloudinary_js_config %>
</head>
Gemfile:
gem 'carrierwave'
gem 'cloudinary'
Application.js:
//= require jquery
//= require jquery_ujs
//= require cloudinary
Uploader:
require 'carrierwave/processing/mime_types'
class ImageUploader < CarrierWave::Uploader::Base
include Cloudinary::CarrierWave
end
Post form:
<%= form_for #post, :html => { :class => "form" } do |f| %>
...
<div class="uploads">
<div class="field">
<%= f.fields_for :images do |builder| %>
<%= render "image_fields", f: builder %>
<% end %>
</div>
</div>
...
<%= f.submit "Save Post" %>
<% end %>
The image_fields.html.erb partial:
<div class="upload">
<%= f.label :file, "Image" %>
<%= f.hidden_field(:file_cache) %>
<%= f.cl_image_upload(:file) %>
</div>
So, this all works great. The images upload direct to Cloudinary and are saved correctly with the post form. However, I don't want a user to be limited to only having three images per post, so I adapted code from Railscast 196 to add additional upload fields with JavaScript.
The CoffeeScript:
jQuery ->
$('form').on 'click', '.add_fields', (event) ->
$list = $('.uploads')
$lis = $list.find('.upload')
newIndex = $lis.length
regexp = new RegExp($(this).data('id'), 'g')
$(this).before($(this).data('fields').replace(regexp, newIndex))
event.preventDefault()
A new add fields link:
(placed underneath the fields_for and inside the div with 'uploads' class)
<%= link_to_add_fields "Add Image", f, :images %>
A new images helper:
def link_to_add_fields(name, f, association)
new_object = f.object.send(association).klass.new
id = new_object.object_id
fields = f.fields_for(association, new_object, child_index: id) do |builder|
render(association.to_s.singularize + "_fields", f: builder)
end
link_to(name, '#', class: "add_fields", data: {id: id, fields: fields.gsub("\n", "")})
end
This seems to work in the sense that the three originally created upload fields continue to work fine (i.e. upload immediately), and clicking the "Add Image" link does generate a new upload field with a successive ID (they are identical other than the ID).
However, the newly generated upload fields don't initiate the upload when a file is selected. Nothing happens. Anybody got any ideas why?
You need to initialize the newly created input field using $(selector).cloudinary_fileupload();

Categories

Resources