Rails 3 Cocoon link_to_add_association Renders Partial Twice - ruby-on-rails-3

My partial gets rendered twice instead of only once, as expected. Any thoughts?
Here's my Person view
<%= simple_nested_form_for(#person) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :name %>
<h3>Records by year</h3>
<div id='records'>
<%= f.simple_fields_for :records do |record| %>
<%= render 'record_fields', :f => record %>
<% end %>
<div class='links'>
<%= link_to_add_association 'New Record', f, :records, :class => 'btn' %>
</div>
</div>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
Models (removed things such as constants and validations):
class Person < ActiveRecord::Base
attr_accessible :name, :records_attributes
has_many :records, :dependent => :destroy
accepts_nested_attributes_for :records, :reject_if => :all_blank, :allow_destroy => true
end
class Record < ActiveRecord::Base
attr_accessible :price, :status, :year, :person_id
belongs_to :person
end
My _record_fields.html.erb partial looks like this:
<div class='nested-fields well'>
<%= f.input :price %>
<%= f.input :year %>
<%= f.input :status, :collection => record_statuses, :include_blank => false %>
<%= link_to_remove_association "Remove", f %>
</div>
An interesting issue is that, if I change where the partials are generated (so 'after' instead of the default 'before' the link_to_add_association link), it generates a partial after the button, but the duplicate is generated before the link_to_add_association link.
The only similar issues reported on here I could find were with caching in production. This is happening in development, and my caching is turned off (by default).
Am I missing something? Can anyone help?
Edit:
Looking at the cocoon JavaScript, it seems the click event is called twice for one click (tested it with $('.add_fields').click(), which triggers $('.add_fields').live('click', function() {...} ) twice. I'm still at a loss as to why this might be happening. Input thoroughly appreciated.
Edit #2:
Controller:
# GET /persons/new
# GET /persons/new.json
def new
#person = Person.new
# #person.records.build
respond_to do |format|
format.html # new.html.erb
format.json { render json: #person }
end
end
# GET /persons/1/edit
def edit
#person = Person.find(params[:id])
end

I was having this same issue.
My problem was I requiring the cocoon javascript twice.
Once in my application.js
// app/assets/javascripts/application.js
//= require cocoon
and once in my application layout
/ app/views/layouts/application.html.haml
= javascript_include_tag :cocoon
after removing the include tag from my layout it began working as expected

Had the same issue, found that in my application layout (app/views/layouts/application.html.erb) I had already included application, and in application.js I had included cocoon. When including application.js in my view with cocoon, cocoon would fire twice.
(Same as above, but slightly different as I didn't explicitly specify cocoon in my application.html.erb, I specified application.js which included cocoon)

This happen when from application.js, you require two times cocoon, commonly, when you try change of jQuery to vanilla Javascript

Related

Rails 3 - checkbox for create (opposite of _destroy)

I have a Query model with a has_many relationship to OutputFields. In my query controller's new function I build several OutputFields within the query instance. In my form, I want each checkbox to determine whether the object is saved (a check means save this instance of OutputField to the database). How can I do this?
my models:
class Query < ActiveRecord::Base
attr_accessible :description, :name
has_many :output_fields, :dependent => :destroy
accepts_nested_attributes_for :output_fields
end
class OutputField < ActiveRecord::Base
attr_accessible :query_id, :column_name, :table_name
belongs_to :query
end
relevant sections of my queries controller. Structure is another model.
# GET /queries/new
# GET /queries/new.json
def new
#query = Query.new
Structure.columns.each do |column|
#query.output_fields.build( :table_name => Structure.table_name, :column_name => column.name )
end
respond_to do |format|
format.html # new.html.erb
format.json { render :json => #query }
end
end
Finally, my view. Right now I'm linking the checkbox to the destroy attribute, which I think will do the exact opposite of what I want.
<%= form_for(#query) do |f| %>
<%= f.fields_for :output_fields do |builder| %>
<div class="field">
<%= builder.check_box :_destroy %>
<%= builder.label :_destroy, builder.object.column_name %>
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
If it's not obvious, I'm trying generate a user interface for a simple query builder. This is my first rails app, so any advice is appreciated.
By default the value of the check_box form helper is to set the checked_value to '1' and the unchecked_value to '0'. So to reverse the behaviour of the destroy checkbox, just switch these values around.
<%= builder.check_box :_destroy, {}, '0', '1' %>

Rails 3 route appends _index to route name even if resource is plural

I have the following routes:
routes.rb:
namespace :admin do
#...
resources :carousel_images
end
controller:
def new
#admin_carousel_image = CarouselImages.new
#...
In view, I render 'form' :
<%= form_for [:admin, #admin_carousel_image] do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
The model:
class Admin::CarouselImage < ActiveRecord::Base
attr_accessible :image
mount_uploader :image, CarouselUploader
end
When I visit /admin/carousel_images/new, I get
NoMethodError in Admin/carousel_images#new
Showing
/home/pinouchon/code/sharewizz/webapp/app/views/admin/carousel_images/_form.html.erb
where line #1 raised:
undefined method `admin_carousel_images_index_path' for
#<#:0xdfe45a4>
I tought that "_index" in the path wasn't appended when the resource is plural. Why is it appended in my case ?
Rails occasionally cannot figure out how to pluralize or detect a plural. Have you tried inflectors? I had a similar case and worked for me.
ActiveSupport::Inflector.inflections(:en) do |inflect|
inflect.irregular 'carousel_image', 'carousel_images'
end
BTW, I am using Rails 5.1.
Change the following and try:
def new
#admin_carousel_image = Admin::CarouselImage.new #CarouselImage is your model name here. It should be singular.
#...
end
In the View, if you are rendering your form from the index.html.erb,
you should have the following:
<%= render 'form' %>
The index file should be in the order of app/view/admin/carousel_images/index
Here the route file find the index.html.erb in carousel_images folder and render the form.

Adding fields to nested forms

So I have a model called City and it has_many :places and it accepts_nested_attributes_for :places. Each Place belongs_to :category. When I render a form for a City I have f.fields_for :places do |place| and I do it like this:
<% f.fields_for :places do |place| %>
<%= render "place_fields", :f => place
<% end %>
My _place_fields.html.erb contains the folowing:
<div class="place_header"><%= f.object.category.name %></div>
<div><%= f.label :name %>: <%=f.text_field :name %> </div>
<div><%= f.text_area :description %> </div>
But the problem apears when I try to add a new place. First of all I want to bring up a simple select form to select a category for the new place, and then render that same partial based on the category_id.
I do that inside the same action:
def add_place
if params[:category_id]
#place = Place.new(:category_id => params[:category_id])
respond_to do |format|
format.html { return nil }
format.js {
#here comes the render
}
end
else
render_message :header => "Choose category", :partial => "category_select", :over => 10
end
end
But if I try to do $("#places_tab").append("<%= escape_javascript(render :partial => "place_fields", :f => #place %>"); it gives an error, wich is expected.
Once again: I need to render the fields for that new Place and just don't know how to do that.
UPDATE
Received some advice on passing the original City Formbuilder to the action and rendering that Place right from that builder, but don't have any idea of how to do that.
The problem is that you are passing an instance of the Place model (#place) as the form builder instead of the form builder itself.

Rails 3 - how to implement changing case of descriptions based on a check_box_tag (not part of model) in before_save callback in external class

I have an rails 3 application where there are multiple registrations (diagnosis, patient, laboratory test, service, client, user, supplier). Initially these will be populated by seeding the database. The requirement is for the description codes to be mixed case (capitalised first word) when either
1. specified by the application (some configuration setting - yet to be determined)
2. specified by data entry user
At present I have a model, view & controller for Diagnosis which contains two fields:
1. code (always to be capitalised)
2. description (First word capitalised based on check_box_tag value)
Presently I am using a before_save callback in the model to implement the conversion, but I cannot get it to only work when the check_box_tag is not selected i.e. its ignoring the check_box_tag.
I have tried changing the check_box_tag to a check_box adding an attr_assessor to the model (but not the sqlite3 db as it is not required to be stored).
This didn't work either.
How do I accomplish this? How do I override the option to use a checkbox from an internal application configuration file which results in either the checkbox being 'unavailable' or not visible if the application configuration specifies not user selectable?
Model (diagnosis.rb)
require 'DescriptionHelper'
class Diagnosis < ActiveRecord::Base
attr_accessible :code, description
string_correct_case = DescriptionHelper.new([:code, :description])
validates :code, :presence => true, :length => { :minimum => 4, :maximum => 4 }
validates :description, :presence => true
before_save string_correct_case
end
Callback in DescriptionHelper.rb
class DescriptionHelper
def initialize(attribute)
#attrs_to_manage = attribute
end
def before_save(record)
#attrs_to_manage.each do |attribute|
record.send("#{attribute}=", capitaliseWords(record.send("#{attribute}")))
end
end
private
def capitaliseWords(value)
value = value.mb_chars.downcase.to_s.gsub(/\b\w/) { |first| first.upcase }
end
end
Controller (diagnoses_controller.rb)
class DiagnosesController < ApplicationController
def new
#diagnosis = Diagnosis.new
end
def create
#diagnosis = Diagnosis.new(params[:diagnosis])
if #diagnosis.save
flash[:notice] = "Diagnosis created with params [#{#diagnosis.attributes.inspect}" #for debugging, once fixed will be just 'Diagnosis created.'
redirect_to #diagnosis
else
flash[:alert] = "Diagnosis not created."
render :action => "new"
end
end
.. other controller actions - edit, show, destroy
end
View (_form.html.erb)
<%= form_for(#daignosis) do |f| %>
<div class="field">
<%= f.label :code %>
<%= f.text_field :code %>
</div>
<div class="field">
<%= f.label :description %>
<%= f.text_field :description %>
</div>
<div class="field">
<%= check_box_tag("diagnosis_desc_dont_convert", 1, false) %><%= f.label "Leave as entered" %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
When this runs currently the check_box_tag is ignored.
When adding in the model an attar_assessor :description_correctcase and changing the view to use f.check_box 'description_correctcase' this is still ignored.
How does one get this to work?
Thanks in advance from a rails aspiring developer.
Finally got a solution to the problem, after reading and re-reading various SO solutions to component parts of my question. I'm not sure its correct in terms of rails, but it works.
If you can offer me a better solution I would certainly learn from this.
Here is my solution.
Model (diagnosis.rb)
require 'DescriptionHelper'
class Diagnosis < ActiveRecord::Base
attr_accessor :do_not_correctcase
attr_accessible :code, :description, :do_not_correctcase
before_save DescriptionHelper.new([:code, :description]), :if =>
lambda { |d| d.do_not_correctcase.to_s == '0' }
validates :code, :presence => true, :length => { :minimum => 4, :maximum => 4 }
validates :description, :presence => true
end
This I referenced from the following SO solution - https://stackoverflow.com/a/6388691/1108010
Controller (diagnoses_controller.rb)
class DiagnosesController < ApplicationController
def new
#diagnosis = Diagnosis.new
end
def create
#diagnosis = Diagnosis.new(params[:diagnosis])
#diagnosis.do_not_correctcase = params[:diagnosis][:do_not_correctcase]
logger.debug "New diagnoses: #{#diagnosis.attributes.inspect}"
logger.debug "Diagnosis should be valid: #{#diagnosis.valid?}"
logger.debug "code has value #{params[:code]}"
if #diagnosis.save
flash[:notice] = "Diagnosis created with params [#{#diagnosis.attributes.inspect}" #for debugging
redirect_to #diagnosis
else
flash[:alert] = "Diagnosis not created."
render :action => "new"
end
end
.. other controller actions - edit, show, destroy
end
I also changed the view to replace the check_box_tag with a check_box.
View (_form.html.erb)
<%= form_for(#daignosis) do |f| %>
<div class="field">
<%= f.label :code %>
<%= f.text_field :code %>
</div>
<div class="field">
<%= f.label :description %>
<%= f.text_field :description %>
</div>
<div class="field">
<%= f.check_box 'do_not_correctcase' %><%= f.label "Leave as entered" %><br />
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
So despite getting this to work I'm not clear on are the following:
When inspecting the attributes with "#{#diagnosis.attributes.inspect}".
I assume that the reason the attr_accessor variable is not included in the New diagnosis output is that it is not part of the database table and therefore Active Reocrd does not instanciate it as part of the new record with #diagnosis.new
Could someone be kind enough to confirm that.
Why does the log have no value for logger.debug "code has value #{params[:code]}"? What causes the params[:code] to be null in the logger output?
Logfile contained the following entry:
Started POST "/diagnoses" for 127.0.0.1 at 2012-03-05 09:36:38 +0000
Processing by DiagnosesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"RW/mzkhavGeaIW0hVLn0ortTnbCDlrX+FfzH4neLLsA=", "diagnosis"=>{"code"=>"tt02", "description"=>"description for tt02", "do_not_correctcase"=>"1"}, "commit"=>"Create Diagnosis"}
New diagnosis: {"code"=>"tt02", "created_at"=>nil, "description"=>"description for tt02", "updated_at"=>nil}
Diagnosis should be valid: true
code has value
I would dearly like to know what is the correct way to do all this, as I feel this is not very DRY or clean.

Voting app in rails 3: how do I link to vote method?

To teach myself Rails, im building an extremely simple Voting app.
There are 2 models, Question and Option. Question has_many Options and Option belongs_to Question.
Using the standard scaffolding, I have reached a stage where you can add a question, view it, and add options to it and see these options.
What I would like to do now is add the code that increases an option.count value by one when clicking on a link. I have a vote_up method in the Option model:
class Option < ActiveRecord::Base
validates :text, :presence => :true
belongs_to :question
def vote_up
self.count += 1
end
end
My Options controller looks like:
class OptionsController < ApplicationController
def create
#question = Question.find(params[:question_id])
#option = #question.options.create(params[:option])
redirect_to question_path(#question)
end
end
My Question model looks like:
class Question < ActiveRecord::Base
validates :text, :presence => {:message => 'A question normally has text...'}
has_many :options, :dependent => :destroy
def vote
# Maybe the vote code will go here???
end
end
And my Question controller has the usual new, create, edit, destroy methods that the scaffold creates. V little customisation here.
My show.html.erb view where I would like to put the link to the vote method looks like:
<p id="notice"><%= notice %></p>
<p>
<b>Question <%= #question.guid %></b>:
<%= #question.text %>
</p>
<% if #question.options.count == 0 %>
<p>Shame! there are currently no options to vote on. Add some! </p>
<% elsif #question.options.count == 1 %>
<p>One option in a vote is a dictatorship... Maybe add some more?</p>
<% end %>
<h2>Options:</h2>
<% #question.options.each do |option| %>
<p>
<%= option.text %>: ** Link to vote here!
</p>
<% end %>
<h2>Add an option to vote on</h2>
<%= form_for([#question, #question.options.build]) do |f| %>
<div class="field">
<%= f.label :text %><br />
<%= f.text_field :text %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
<% if #question.options.count == 0 # Only show edit if no options saved. %>
<%= link_to 'Edit', edit_question_path(#question) %> |
<% end %>
<%= link_to 'Back', questions_path %>
So what I am trying to do is add a "vote" link next to each option that calls the vote_up method in the options model. This is probably laughably easy, but i've hit a wall and would really appreciate any help.
Also, any suggestions on how to do this better would be welcome!
Thanks
Simon
I think #oded-harth has showed a right way, but I have two remarks:
First of all, Rails is a beautiful language and is written to simplify our developer lives ;) When programming in Rails you must never forget that. With this in mind, I want to point you to "increment()" method. So you can simply up-vote without unnecessary += 1. To down-vote use decrement(). I believe you can use it like this: option.increment(:count)
Second, I think it's a little dirty to have a whole form for a simple vote action. You can use something like this
<%= link_to "Vote Up", :url => { :action => :vote_up, :option_id => option.id }, :method => :put %>
To make it work you'll have to set your route something like this:
resources :votes
put :vote_up
end
What I would do is make the vote_up method in the controller:
def vote_up
option = Option.find(params[:option_id])
option.count += 1
redirect (to where do you want...)
end
And in the view I would call that method this way:
<%= form_for( option, :url => { :action => "vote_up", :option_id => option.id} ) do |f| %>
<%= f.submit("vote up") %>
<% end %>