Has controller action specific layouts changed in Rails 4.1 - ruby-on-rails

I've just upgraded to Rails 4.1.
I previously had the following in a controller action, which worked perfectly.
respond_to do |format|
format.html { render html: #user, layout: "fullscreen" }
end
This is not working in Rails 4.1, and the page simply renders the object #<User:0x007fb087429a70>
Edit the controller as follows fixes this error.
respond_to do |format|
format.html
end
What is the correct way to set the layout in Rails 4.1. I'm having trouble finding this in the docs.

html option was added in render method in Rails version 4.1. See the issue listed here
When you tried
def action_name
## ...
respond_to do |format|
format.html { render html: #user, layout: "fullscreen" }
end
end
in a Rails version prior to v4.1, what really happened was render ignored the html option, picked up the layout and went ahead to look for a view named action_name.html.***(where *** refers to template handler like erb, haml, etc). It found the view and rendered it. If the view didn't exist then you would have received a Missing template error
And when you use the same code in Rails 4.1, as the html option is allowed in render method it will definitely be processed. Now, first you need to understand what the html option actually does:
You can send a HTML string back to the browser by using the :html
option to render:
render html: "<strong>Not Found</strong>".html_safe
You use this when you don't want to write an html file for your action and wish to simply render a HTML string.
Which is the reason when this particular action is called you now see an html page with object #<User:0x007fb087429a70> because you passed the value to html option as #user.
Edit the controller as follows fixes this error.
respond_to do |format|
format.html
end
Firstly, it was not an error. You misinterpreted what html option does. I am pretty sure you do have a view corresponding to your action which is what you expected to be rendered. The above code does that for you.
I suppose you simply wish to specify layout for your view. All you need to do is:
respond_to do |format|
format.html { render layout: "fullscreen" }
end

Related

How to use Ajax to make a request and update the data within a table?

I have table that is filled with data from an instance variable. How would I use Ajax to make a request and update the data within the table to reflect the new data for the instance variable?
As a general answer, Rails comes with some great helpers to make working with Ajax quite simple. I suggest reading up on the Rails Guides for in depth coverage on this topic.
To trigger a specific controller action via Ajax, you can do something like this:
Somewhere in your table view, where appropriate:
<%= button_to "Do Something!", [:your_action, #example], remote: true %>
Then in your target controller:
def your_action
#Do whatever you wish here
respond_to do |format|
format.html { redirect_to #example, notice: 'Action successfully performed.' }
format.js {}
end
end
The format.js in the respond_to block allows the controller to respond to the Ajax request. You can then create a respective app/views/examples/your_action.js.erb file that generates the JS that will be sent/executed on the client side:
$("<%= escape_javascript(render #example) %>").appendTo("#your-table-element");

Why is my Rails app redirecting to `data:,`?

So when I save a record in my Rails 4 app this happens. Here's some details:
I'm using the Ace editor.
The data attribute is no where in my model or app.
The form is a standard form_for (not remote).
The record does save successfully but then it redirects to this weird ass URL.
The code for the update is standard scaffold boilerplate.
# PATCH/PUT /pages/1
# PATCH/PUT /pages/1.json
def update
respond_to do |format|
if #page.update(page_params)
format.html { redirect_to #page, notice: 'Page was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #page.errors, status: :unprocessable_entity }
end
end
end
Anyone have any ideas? Probably something simple but I can't for the life of me figure this one out. Let me know if there's any other pertinent information I can share.
In your specific case (the one shown in your quickcast), Chrome is considering this a security risk because you're submitting a <script> element containing javascript that's being inserted into the renderable contents of the page using [Rails' built-in] asynchronous javascript.
To avoid this, you could:
Strip out the wrapping <script> tags using client-side logic before submitting the form, and then add them back in on the server before saving the record.
Disable Rails' built-in ajaxification of the update action in this controller, so that it submits through plain old HTML
Add an intermediary redirect page between form submittal and viewing the show action
I believe it is because your #page show view is rendering escaped HTML and Javascript. Chrome probably has heuristics to analyze the page and determine what type of document it is. Since it likely doesn't start with <html>, then Chrome assumes it is a data file with the data: protocol. Try rendering to a string and printing the results on the console:
http://guides.rubyonrails.org/layouts_and_rendering.html#using-render
puts render_to_string #page
See section 4.1.1 http://guides.rubyonrails.org/security.html#redirection
data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K
Please update your answer with the show view template, the show action, and the log from render_to_string.

jquery ajax render partial with rails view

I have my jquery ajax success as
success: function(data) {
$('#someId').html(data);
}
I have a partial file in the name of _information.html.erb
How do i render my ajax success response to rails partial view(information).
Most of the resources showing something like this
$('#holderDiv').empty().append('<ul> <%= j render #comments %> </li>')
But i didn't feel comfortable with it. Any other way to solve it.
UPDATE
Here's some more info in response to your comments.
First please read this Rails Guide on Javascript for more info.
update.js.erb is your view. Instead of having an update.html.erb file for your view, the respond_to block with format.js in your controller will send update.js.erb (formatted as javascript code) back to your jquery function.
update.js.erb could contain pure javascript. However it is processed by the server before being converted to javascript, so you can embed any ruby code you want. That ruby code gets converted into javascript.
If you use chrome developer tools, you can look in the "network" tab after your jquery call runs. You'll see a new entry appear for the AJAX call you just made. If you click on the entry, you'll see the javascript that was returned.
I've updated the update.js.erb file below slightly to show how you can put regular javascript code in the .js.erb file. The first line is javascript. The second line is ruby code which the server converts into javascript. So by the time that it gets to your browser, the entire update.js.erb file has been converted into javascript.
Hope that helps...
Original Answer Below:
Option 1:
Assuming that your jQuery success function is tied to the successful completion of a controller action (I'll use the edit action for my example), you would create a view called update.js.erb which will be called after a successful edit.
Controller:
if #user.update_attributes(params[:user])
respond_to do |format|
format.html { redirect_to #user, notice: "Successfully updated user." }
format.js
end
else
# ...
end
Because this is being called from javascript and you have format.js in the respond_to block, update.js.erb will automatically be called.
update.js.erb:
console.log('see... this is a regular javascript call.');
<%= render partial: 'information', format: 'js' %>
Option 2
The snippet you included:
$('#holderDiv').empty().append('<ul> <%= j render #comments %> </li>')
will only work in a js.erb file, where embedded ruby code is first processed then converted into javascript code. That would work in a situation such as:
Controller:
def create
user = User.new(params[:user])
respond_to do |format|
if #user.save
#comments = 'some comments to display!'
format.js
else
# ...
end
end
end
create.js.erb:
$('#holderDiv').empty().append('<%= j render #comments %>')

How to render erb template to string inside action?

I need a string of html (something like "<html><body>Hello World</body></html>") for faxing purpose.
I wrote it into a seprate erb file: views/orders/_fax.html.erb ,
and try to render the erb in action: html_data = render(:partial => 'fax').
Here is part of the controller that raises the issue:
respond_to do |format|
if #order.save
html_data = render(:partial => 'fax')
response = fax_machine.send_fax(html_data)
......
format.html { redirect_to #order, notice: 'Order was successfully created.' }
format.json { render json: #order, status: :created, location: #order }
else
format.html { render action: "new" }
format.json { render json: #order.errors, status: :unprocessable_entity }
end
end
It gave me an AbstractController::DoubleRenderError as below:
AbstractController::DoubleRenderError in OrdersController#create
Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like "redirect_to(...) and return".
How to solve this problem?
If you only need the rendered HTML, and don't need any functionality from the controller, you might try using ERB directly within a helper class, eg.:
module FaxHelper
def to_fax
html = File.open(path_to_template).read
template = ERB.new(html)
template.result
end
end
The ERB docs explain this in more detail.
EDIT
To get the instance variables from the controller, pass the binding into the result call, eg:
# controller
to_fax(binding)
# helper class
def to_fax(controller_binding)
html = File.open(path_to_template).read
template = ERB.new(html)
template.result(controller_binding)
end
Note: I've never done this, but it seems workable :)
Use the #render_to_string method
it works the same way as the typical render method but useful when you need to add some templated HTML to a json response
http://apidock.com/rails/ActionController/Base/render_to_string
If you don't want to escape html, just call .html_safe on it:
"<html><body>Hello World</body></html>".html_safe
Re your error, please post your OrdersController - looks like you are calling render or redirect more than once in the create action.
(Btw, just in case you are trying it - you can't render a partial in a controller - you can only render partials in views)
Edit: yeah your problem is you trying to render a partial in the controller action. You could use an after_create callback to set up and send the fax - though again you won't want to use a partial (as they are for views). http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html
Edit: for your fax problem,you could create a normal Ruby Class, see this excellent bit of advice from Yehuda: https://stackoverflow.com/a/1071510/468009
The reason is you cannot render or redirect inside the same action more than once at a given time.
But in your code, you have both render and redirect. I think in your controller you can use simply only the render, assuming you don't need any json output.
Try this
def create
#order.save
render(:partial => 'fax')
end
I haven't tested this, but I guess you get the idea :), and think about a way to handle errors as well (in case order didn't save).

How to redirect after a successful AJAX form submission (Rails 3.2)

Suppose you have an edit form with :remote => true. Your controller method looks like
def update
#article = Article.find(params[:id])
respond_to do |format|
if #article.update_attributes(params[:article])
format.html { redirect_to #article}
format.js { render :js => "window.location.replace('#{article_path(#article)}');"}
else
format.html { render :action => "edit" }
# Render update.js.erb which replaces the body of the form
format.js {}
end
end
end
What's the best way to do the redirect on successful article update in Rails 3.2.1? The raw JS solution seems a little sleazy, but I do like the fact that it's obvious that it's performing the same function as the format.html version.
I would prefer a solution that does not use RJS (if that even works in Rails 3.2?)
How about adding the below line of code on the view file itself
#some_file.js.erb
`window.location = redirect_path
As you mentioned in the question you do not prefer RJS, but I think it's better to follow this pattern better than writing the js code in the controller.
Does your ajax interact with a model (.php,.asp?). My preferred method in this instance is to create a success/fail criteria within the model after submission and redirect directly from there. Not sure if that makes sense in this application though?

Resources