How to render flash messages when remote true - ruby-on-rails

I have a time logger controller method that calls from my view, called _embed_menu.html.erb
<%= link_to l(:start_time_logger) + ' #' + #issue.id.to_s + ' ',
{:controller => '/time_loggers', :action => 'start', :issue_id => #issue.id},
:class => 'icon icon-start',
:"data-replace" => '#time-logger-menu',
:remote => true
%>
The part of 'start' method, where I shown an error:
respond_to do |format|
format.js{ flash[:error] = l(:start_time_expired_error)}
end
Now to the part of the rendering flash messages. application_helper.rb
Have render_flash_messages function.
def render_flash_messages
s = ''
flash.each do |k,v|
s << content_tag('div', v.html_safe, :class => "flash #{k}", :id => "flash_#{k}")
end
s.html_safe
end
and that function called on base.html.erb template.
<%= render_flash_messages %>
So the result - I launch a start method and flash shown only after I reload the page. I also tried to redirect with the hope that after this redirect the error will show.
redirect_to controller: 'issues', format: 'js'
but no result.
Maybe I can trigger re-rendering of <%= render_flash_messages %>?

What happens when you click a remote: true link is that Rails creates a request for text/javascript and then runs the resulting javascript in that page.
Usually a js.erb template contains some javascript that modifies the document:
$("<%= escape_javascript(render #user) %>").appendTo("#users");
So if you want to alter the flash messages on the page you need to target the wrapping element and append it:
$("<%= escape_javascript(render_flash_messages) %>").appendTo("#flashes");
This assumes you have a wrapping element around the flash messages. Otherwise just add one to the layout.
<div id="flashes">
<%= render_flash_messages %>
</div>

Use flash.now[:error] if you need to use the flash message on the same request.
https://api.rubyonrails.org/classes/ActionDispatch/Flash/FlashHash.html#method-i-now
https://guides.rubyonrails.org/action_controller_overview.html#flash-now

replace flash to flash.now.
for example,
respond_to do |format|
format.js{ flash.now[:error] = l(:start_time_expired_error)}
end
and in js.erb file re-render the partial where you want to update.

I just manually redirect to the page by window.location solution - here I just call issues index controller, but here can any link.
flash[:error] = l(:start_time_expired_error)
respond_to do |format|
format.js{ render js:"window.location='/issues/"+#issue.id.to_s+"'"}
end

Related

Getting "Template is missing" error when attempting to render js.erb file

I'm new to Rails, and I'm having an issue where I can't render a .js.erb file. I think the root of the issue is that Rails' internal routing mechanism expects me to name and configure my files just so, but I'm missing one or two pieces, and I'm not sure how to look for what needs to be fixed.
I have an HTML view with a link to a controller action:
<%# snip %>
<div id="holding_issues_list">
<%= link_to "Show issues on hold", {
:action => "show_user_issues",
:controller => "support",
:issue_type => "holding",
:user_id => #user.id },
:remote => true %>
</div>
<%# snip %>
I think (but I'm not sure) that :remote => true causes the link to make an AJAX call.
This is the corresponding controller action in the controller app/controllers/support_controller.rb:
def show_user_issues
#target_div = params[:target_div] || "holding_issues_list"
user = User.find(params[:user_id])
issue_type = params[:issue_type]
#snip - set the value of #issues
end
I want this file, named show_user_issues.js.erb and placed in app/views/support, to be rendered when the controller exits:
$("#<%= #target_div %>").show();
alert('test');
$("#<%= #target_div %>").html(
"<%= escape_javascript render :partial => '_show_user_issues', :locals => {:target_div => #target_div, :issues => #issues} %>");
This is app/views/support/_show_user_issues.html.erb, the partial I want show_user_issues.js.erb to render:
<% for issue in #active_issues %>
<div id="issue_<%= issue.id %>_display">
<%= render :partial => 'show_issue_mini', :locals => {:issue => issue} %>
</div>
<% end %>
When I try clicking the link in my original HTML view, nothing happens. When I open it up in a new tab, I get this error message:
Template is missing
Missing template support/show_user_issues,
application/show_user_issues with {:locale=>[:en],
:handlers=>[:builder, :erb], :formats=>[:html]}. Searched in: *
"/home/<>/app/views" *
"/home/<>/gems/kaminari-0.14.1/app/views"
The alert('test') that I put into show_user_issues.js.erb doesn't show up, so I think that Rails is getting hung up on rendering that file - that is, the routing mechanism can't find it. How can I correct this issue?
P.S. I double-checked that I put in all the file names exactly as they are in the code base.
Change your controller action to handle the type of request.
def show_user_issues
#target_div = params[:target_div] || "holding_issues_list"
user = User.find(params[:user_id])
issue_type = params[:issue_type]
#snip - set the value of #issues
respond_to do |format|
format.js
end
end
This will check the format of the request which is .js in case of :remote => true. So it will handle it by rendering the show_user_issues.js.erb file.
A couple other problems that I ran into after applying Manoj Monga's answer that I suspect other new Rails devs might run into:
In show_user_issues.js.erb, I had
[...].html("<%= escape_javascript render :partial => '_show_user_issues',[...]
The underscore before '_show_user_issues' caused the ERB builder to fail. It should have just been 'show_user_issues'.
In _show_user_issues.html.erb, I had
<% for issue in #active_issues %>
If you look closely at show_user_issues.js.erb, though, I named the variable #issues, not #active_issues:
[...]:locals => {:target_div => #target_div, :issues => #issues}[...]
So I changed the line in the HTML partial to
<% for issue in #issues %>
After these last couple changes, the new functionality I was adding worked as expected.

where does render :partial html end up

I have a view with an ajax form:
<%= form_tag( {:action => 'some_action'}, {:remote => true}) do %>
...
<%= submit_tag "Submit" %>
<% end %>
Now, in the target action, I want to display a partial
def some_action
# some logic
render :partial => "some_partial"
end
The partial is just html. _some_partial.html.erb could be
<br>Hi, this is the partial</br>
When I submit the form, I see the html response packet is received in the browser (with firebug's net logs), but the html doesn't show up anywhere. Where should the html be? How to render a partial html view from an action?
you are rendering a partial but not specifying where to render it.
in rails 2 you could do it with:
def some_action
# some logic
render :update do |page|
page.replace_html 'some_div_id', :partial => 'some_partial'
end
end
but in rails 3, above code is no longer valid.
see Unobtrusive Javascript
create a file named some_action.js.erb and write the code in it:
// update div with id some_div_id
$("#some_div_id").html("<%= escape_javascript(render :partial => 'some_partial') %>");
in controller
def some_action
# some logic
respond_to do |format|
format.js
end
end
I figured out how to send and display html. From theReq, just add :remote => true, "data-type" => "html" to the form and then in the javascript of the page, capture the returned html on ajaxSuccess to display it:
$('form#whatever').on('ajaxSuccess', function (event, data, status, xhr) {
$('div#target').html(data);
}
)

Prawn + Prawnto Issue

I know prawn is working because I have a show action that if I add .pdf on to the end of it loads show.pdf.prawn. However, I have a form:
<%= form_tag(:controller => "/holders", :action=> "generate", format: "pdf") do %>
<%= label_tag(:count, "How Many Students?") %>
<%= text_field_tag(:count) %>
<%= hidden_field_tag :holder_id, value: #holder%>
<%= submit_tag("Generate Course Lesson") %>
<% end %>
That submits count to the the generate action.
Inside my generate action I have the following:
def generate
prawnto :filename => "print.pdf"
respond_to do |format|
format.html
format.pdf { render :layout => false}
end
end
and my generate.pdf.prawn looks like:
pdf.text "HELLO WORLD"
When I submit the form I get the URL: http://localhost:3000/generate.pdf and Chrome tells me
Failed to load PDF document with no other errors or information.
I noticed I am getting: Rendered holders/generate.pdf.erb in my dev logs which indicates its not even looking for the .prawn file.
What am I doing wrong?
Setup your action like this:
def generate
respond_to do |format|
format.html
format.pdf { prawnto :filename => 'print.pdf' }
end
end

Loading a Partial via Ajax in Rails 3

I am having a problem getting the page to update. I am completely lost and don't know where to start. My form for does have a :remote=>true The page initialy loads with a partial wrapped in a div tag called comments. I don't know what to place in the controller or what file to create, or even how to create it, to update the partial when the user clicks submit on the form. Thanks for any help.
Travis,
I'm not sure which action you're trying to perform here exactly, so let's assume you want to create a new resource.
Let's assume your resource is called Post
If you used rails to generate your PostController, you'll have a method create in there.
It may look something like this:
def create
#posts= Post.new(params[:post])
respond_to do |format|
if #post.save
format.html { redirect_to(#post, :notice => 'Post was successfully created.') }
format.xml { render :xml => #post, :status => :created, :location => #post}
else
format.html { render :action => "new" }
format.xml { render :xml => #post.errors, :status => :unprocessable_entity }
end
end
end
The key part here is that you'll need a format.js in the respond_to block.
When you put a :remote => true flag on your forms or links, you're telling rails that you want to make the request via Ajax. This results in a data-remote attribute being placed on your form or a element and that is in turn used to tell the unobtrusive Javascript to use Ajax to submit your request.
What you need to make sure is present on your end are the following:
In your controller, make sure there is a format.js response format listed in the respond_to block (see example above for html and xml.
Second, we're going to create a create.js.erb file under your app/views/posts folder. By default, rails will look for a action.format.erb file that corresponds to your action and format.
In the app/views/posts/create.js.erb file, you can now place your response javascript that will update your HTML document accordingly. If for example, you had a list of posts and you wanted to add a newly created one to the end of it, you may have something like this:
app/views/something/show.html.erb
<h1>Posts</h1>
<div id="posts">
<%= render #something.posts %>
</div>
<!-- here we will include the :remote => true option, which will add a data-remote attribute to our form -->
<%= form_for Post.new, :remote => true do |f| %>
<%= f.text_area :text %>
<%= f.submit %>
<% end %>
app/views/posts/create.js.erb
// here we're taking our newly created post and appending it to the list shown above
$('#posts').append("<%= escape_javascript(render #post) %>");
Finally, let's assume our post partial is something like this
app/views/posts/_post.html.erb
<p class="post-text"><%= #post.text %></p>
I'm not sure what javascript framework you're using, but here I'm using jQuery. I believe if you're using rails 3.1, jQuery is the default framework used, otherwise you'd have to look at jquery_ujs.
Hope this helps.

How to make the page not redirect in Rails

I have an erb file named index that has a form in it. As a simple example:
<% form_for #foo, :url => {:action => 'bar'} do |f| %>
<%= f.submit "BAR!" %>
<%end%>
When I click the BAR! button it preforms the actions I expect and it forwards me onto the bar.erb file, displaying the expected output. What I would like to be able to do, however, is to take the generated html from this page and stuff it into the innerHTML of a div on the index page. I assume there is a way but I must ask, is there a way to achieve this? Are there any examples available that would be helpful? Thanks!
You should be able to pass the id of the div to update like so:
<% remote_form_for #foo, :url => {:action => 'bar'}, :update => 'id-of-div-to-update' do |f| %>
<%= f.submit "BAR!" %>
<%end%>
In the controller:
def bar
# your code here
respond_to do |format|
format.html { redirect_to(xxx) }
format.js
end
end
Rails will look for a template named bar.js and will render it and return it's content to the browser without a redirect.

Resources