Displaying validation errors with Ruby - ruby-on-rails

I'm having some trouble rendering validation messages using "remote => true"
I have a partially rendered form for saving an address
<%= render :partial => "registrations/address", :locals => {:address => #user.customer_addresses.build, :is_new => true, :checked => false} %>
In this form, the user clicks this button to create a new address
<%= link_to "Save Address", "javascript://", :remote => true, :data => "new", "data-target" => create_user_address_url, "data-method" => "Post" %>
I have the 'create_address' function set up in the controller (which returns the validation errors), as well as a create_address.js.erb file. However, it doesnt seem like the browser is executing anything in the js file.

It would be great to see the code of js.erb file
But I assume you have escape javascript issue.
Just use j in your render partial method. E.g.
<%= j render('partial_name') %>

You might have forgot to reload the partial which show the error message. After using remote => true you need to reload the partial so that the changes will reflect on that partial.

Related

In Rails when using AJAX, how to change the js file it loads?

For example, I use data remote for the pagination like this :
<%= paginate #products, :remote => true %>
It works. But the problem is I have multiple lists to paginate in one page. So, I need a way to send the call to a separate files so I can render the appropriate content. How can I do this?
My index.js.erb :
<% if params[:list] %>
$('#products').html('<%= escape_javascript render(#products) %>');
$('#paginator').html('<%= escape_javascript(paginate(#products, remote: true, param_name: 'list' ).to_s) %>');
<% end %>
For this you need to add another param with paginate.
<%= paginate #products, :remote => true, :param_name => param_name %>
This params name will pass as parameter to controller so you can control which ajax pagination you are calling.
If you are calling same action then on the basis of param name you can change the value of #products also. One more thing you need to consider in your xxxx.js.erb file you need to render paginate object also.
In your js file you can change html on the basis of param also.
- if params[:xxx]
$('#xxx').html('#{escape_javascript render(:partial =>"partial_name",:locals => { :posts => #products, :param_name => 'xxx'})}');
$('#xxx #paginator').html('#{escape_javascript(paginate(#products, :remote => true, :param_name => 'xxx').to_s)}');
- if params[:yyy]
$('#yyy').html('#{escape_javascript render(:partial =>"partial_name",:locals => { :posts => #products, :param_name => 'yyy'})}');
$('#yyy #paginator').html('#{escape_javascript(paginate(#products, :remote => true, :param_name => 'yyy').to_s)}');
In your controller you should use param_name instead of params page

IE9 nested simple_form_for with haml

I have a page That starts with a form. Inside that form, I render another page called information. Inside this render I have another render for a modal. This modal is another form. So at this point i have one nested form. This works great in all browsers except IE9. I think what IE9 is trying to do is it sees when the second form is ending, and it also ends the first form, so everything that is after the nested form is screwed up.
Has anyone else ran into this problem? and how do you fix it?
Parent File (form):
= simple_form_for #form do |f|
#the_form
= render 'information', :f => f
.buttons
%input{:name => "submit", :type => "submit", :value => "SUBMIT"}
%input{:name => "cancel", :type => "submit", :value => "Cancel"}
Render information file:
#information
%fieldset
%legend
Form Title
= f.input :form_id, :url => form_name_path, :label => 'Field Name'
= render 'modal'
(the rest of the code here breaks)...
Render modal file:
.modal.hide.fade
.modalBox
%h3
New Form Name
%a{href: "#", class: "x", title: "Close" : 'data-dismiss' => "modal"}
.diagRepeater
.modal-body
= simple_form_for Form.new, :url => {:controller => :form, :action => :modal_create} do |o|
=o.input :name, :label => 'Name', :required => true
=o.input :form_id, :as => :hidden
It is in this last file that I see the problem. If I comment out the simple_form_for and on, it will work great. If I leave it, it will break the rest of the form.
HTML not support nested form.
You can have several forms in a page but they should not be nested.
As you say: this work great in all browser for me it is miracle because 'You would even have problems making it work in different versions of the same browser' so avoid using that.
Webkit explain why HTML not supporting nested form
bool HTMLParser::formCreateErrorCheck(Token* t, RefPtr<Node>& result)
{
// Only create a new form if we're not already inside one.
// This is consistent with other browsers' behavior.
if (!m_currentFormElement) {
m_currentFormElement = new HTMLFormElement(formTag, m_document);
result = m_currentFormElement;
pCloserCreateErrorCheck(t, result);
}
return false;
}

kaminari pagination ajax call renders to wrong controller

First we start off with conversations/index.html.haml to create a message
#new_message_conversation
.panel.panel-info
.panel-heading
%h4 Send a Bark!
.panel-footer(style="padding-top: 20px")
= simple_form_for :message, url: :messages, :remote => true do |f|
.form-group
= f.input :master_name, placeholder: 'Choose master...', label: false, :url => autocomplete_master_name_conversations_path, :as => :autocomplete, id_element: "#master_name_id", input_html: {class: "form-control"}
= f.input :recipient_id, as: "hidden", input_html: {id: "master_name_id"}
= f.input :body, label: false, as: "text", placeholder: 'Write message...', :input_html => { :rows => 5 }
= f.button :submit, 'Send', :class => "btn btn-lg btn-primary", :disable_with => "Sending..."
which then goes to the messages#create action which has
...
respond_to do |format|
format.js { render "create", locals: { conversation: #conversation, conversations: #conversations, receipts: #receipts }}
end
...
which sends the work to the conversations/create.js.erb file
$('#new_message_conversation').prop('disabled', true).html("<%= raw escape_javascript(render(:partial => 'conversations/show', locals: { conversation: conversation, receipts: receipts })) %>").hide().fadeIn('fast');
which adds the conversations/show partial, _show.html.haml which has
...
%ul.pager.pull-left(style= "padding-left: 10px")
%li#paginator_3= link_to_previous_page #receipts, "Newer", :remote => true, :param_name => 'page_2'
%li#paginator_4= link_to_next_page #receipts, "Older", :remote => true, :param_name => 'page_2'
...
everything works excepts now the pagination buttons don't work. and when I click a pagination button the server says
Rendered messages/index.js.erb
Why does a partial that's in views/conversations that has a remote ajax call render to a different controller (messages)? It should be rendering conversations/show.js.erb because the partial is conversations/_show.html.haml right?
here are my routes also
...
resources :conversations do
get :autocomplete_master_name, :on => :collection
end
resources :messages
...
Even though you're rendering views and partials from the conversations path, you never even touched the ConversationController.
You can render whatever views you want for the action you're executing. The only thing connecting the ConversationController with the views/conversation/file.html.erb and similar view files is a loose naming convention. When rendering say render 'index' from an action of the ConversationController, it just assumes by that convention you meant the views/conversation/index.html.erb file.
Your view or partial alone cannot reference the controller it would belong to (when going by the naming convention) because it is just used as a template by the render command in your action. The view doesn't care whether the controller behind it is the appropriate one. In this case, the render was originally executed in the MessagesController, so the view also just has a reference to that one.
To still have the links point to the correct controller, you need to specify the controller to be used for the url. Otherwise, it is assumed that you want to use the very same controller you used to render the page.
The culprit is probably somewhere in the link_to_previous_page and link_to_next_page helpers by kaminari. When using the full paginate helper, you can set the controller and action you want to use like this:
<%= paginate #users, :params => {:controller => 'foo', :action => 'bar'} %>
The documentation (here: https://github.com/amatsuda/kaminari) doesn't say whether this param is also possible with the other helpers, but the helper uses a simple link_to (see here: https://github.com/amatsuda/kaminari/blob/master/lib/kaminari/helpers/action_view_extension.rb), so you should be able to do something like this:
link_to_previous_page #receipts, "Newer", {:controller => 'foo', :action => 'bar', :remote => true, :param_name => 'page_2'}

Issue with using link_to :remote - Rails 3

I am using link_to :remote to update one of the div elements on the HTML. This is just a beginner's code. However, the update does not occur on clicking the link. Here is the code:
class SampleController < ApplicationController
def updater
render :text => Time.now
end
end
this is the list.html.erb:
<script type = "text/javascript" src = "/javascripts/prototype.js">
<%= link_to "Hello Testing",
:update => "test_id",
:url => {:action => 'updater'},
:remote => true
%>
<div id="test_id"></div>
So on click the link "Hello Testing", the URL in the browser changes to:
http://localhost:3000/samples?remote=true&update=response_id&url[action]=updater
However, the div element that I am trying to set to the current time does not occur on the UI. What can be the issue here?
Updated the post with:
routes.rb: http://pastebin.com/wmKsa1DD
Generated HTML Code : http://pastebin.com/stU3FpL8
HTML Response in Firebug: http://pastebin.com/WjsB7zAh
Using url_for does not change the behaviour.
please use url_for:
<%= link_to "Hello Testing", url_for(:action => :updater),
:update => "test_id", :remote => true %>
I'm not 100% sure, but I don't think that :update is going to work, since Rails3 now mainly relies on ujs.
The "rails way" to update your div would look like (jquery) :
$('div#test_id').bind('ajax:complete', function(event, xhr) {
$(this).html($.parseJSON(xhr.responseText));
})
1: You should include also rails.js file. Ordinary in Rails it makes like this:
<%= javascript_include_tag :defaults %>
2: I prefer to use this naming for urls: updater_samples_path or [:updater, :samples]
3: You should show your routes. If updater method using not GET method, then you should define it:
<%= link_to "Hello Testing", :update => "test_id", updater_samples_path, :method => :put, :remote => true %>
4: Use FIREBUG to se your AJAX responses. So you can easily debug your app. Also you can show us its response, so we will better understend situation

updating a select box based on another (Ruby on Rails)

I'm in need of a more complete example on how to update a select box based on the results of a second select box in Ruby on Rails. I asked about this already here. I've read through the feedback from that posting, but am not having any luck figuring this out, and I've been trying for hours. Anybody know of a better (and more complete) example?
This is generally handled in Javascript. I don't particularly enjoy coding Javascript, so what I do for this in my application is to use a form_observer (a Rails helper which uses the Prototype Javascript library to watch your form for input changes) and have update a DIV in the HTML containing the second select box, based on the results of an AJAX call. Since AJAX talks to my server, I can write arbitrarily complex logic in Ruby to render the new HTML.
Example code:
#goes in view
<%= Code to render the first list box. %>
<%= render :partial => 'second_list_box_partial', :locals => {:selected = insert_magic_here } %>
<%= observe_field(:first_list_box,
:url => { :action => :second_box_ajax }),
:frequency => 0.5,
:update => :second_list_box_div,
:with => %Q| 'value=' + $('first_list_box').value; |
%>
#goes in controller
def second_box_ajax
first_box_value = params[:value]
#magic goes here
#selected = #more magic
render :partial => 'second_list_box_partial', :locals => {:selected => #selected}, :layout => false
end
#goes in partial
<div id="second_list_box_div">
Actual code to render list box goes here.
</div>

Resources