Hacking RJS behaviour in Rails 5 - ruby-on-rails

I have a old rails 2.x project that I have converted mostly over to rails 5.
One issue is some of my actions used RJS, so it looked like:
if request.xhr?
render :action => 'new_user' and return
end
The new_user.js.rjs looks something like:
page.call "User.create", render(:partial => 'new_user'), {:userId => #user.id}
Looking at the response in chrome I can see it is just returning:
User.create('<tr><td>....</td></tr>', {"userId" : 123});
I only have to support the page.call type RJS call, what would be a easy "hack" to get this to work in rails 5?
I don't want to modify all of my javascript code, I just need to basically have a javascript block that I pass the JS code to in my view pages right?

Try to render a response as a string:
if request.xhr?
render render_to_string partial: 'new_user',
locals: { userId: #user.id },
layout: false
end
Or try to use format handler instead:
respond_to do |format|
format.rjs do
render render_to_string partial: 'new_user',
locals: { userId: #user.id },
layout: false
end
end

I ended up returning a JSON response to my view pages like this:
some_partial_html = render_to_string(:partial => 'something')
response = {
"html": some_partial_html,
"a" : 1
}.to_json
render json: response
And then in my view I used the json response values as arguements to the javascript object that performs the functionality I needed.

Related

Rails rendering layout only?

Just trying out a simple rails app, mostly going for an API backend with JSON, heavy client side app. So what i want to do is only render the layout, and have javascript code handle the url, and make the ajax request to get the json data. The following seems to work:
respond_to do |format|
format.html { render :nothing => true, :layout => true }
end
However, since nothing is meant to render nothing, it feels kinda wrong. Is there a more proper way to just render the layout? Note that my layout does not have a yield.
Well, this worked for me in Rails 4.0:
render :text => "", :layout => true
(Copying Vasile's comment for better visibility.)
For rails 5.1, in order to render the layout without requiring a view template, you need to use
def index
render html: '', layout: true
end
or with a custom layout
def index
render html: '', layout: 'mylayout'
end
Per tfwright, this will also work:
def index
render html: nil, layout: true
end
However, the following will not work:
render text: '', layout: 'mylayout' will give you an error because the view template index.html.haml does not exist.
render nothing: true, layout: 'mylayout' will give you an error because nothing:true is deprecated, and the index template does not exist (however, this works in rails 4.2)
render body: '', layout: 'mylayout' will render '' (no layout)
render plain: '', layout: 'mylayout' will render '' (no layout)
render :file => "layout_file", :layout => false
Try this, this will render the response to a file called sample.html which could be a static html file.
and also you could have this file in a common location, so that you could loaded it to all the actions
have your static content in this page, and if you need a dynamic page you could have a .erb page too
in your method
def index
#posts = Post.all
respond_to do |format|
format.html {render :file => "posts/sample"}
format.json { render json: #posts }
end
end
/post/sample.html
HTH
I needed something similar-- to display a layout template with no partial (where partials are handled clientside).
rails 4.2.0
respond_to do |format|
format.html { render text: nil, layout: true }
end
I believe if your application is just fetching JSON from the server, the format should be json and not html.
respond_to do |format|
format.json #your_collection
end
Or put the format for all actions in your controller and just respond with the objects.

Rails render JSON using <%= not working as expected

I'm currently trying to return multiple JSON objects in one of my controllers as such.
#chromosomes = #organism.chromosomes.to_json
#file_data = current_user.files.to_json
respond_to do |format|
format.html
end
However, on the front end when I do:
<%= #chromosomes %>
or
<%= #file_data %>
I don't get a JSON object, instead I get the data as a string with things such as &quote, etc. I've tried parsing the string such as
console.log($.parseJSON("<%= #chromosomes %>"));
but it still isn't working. Is this is because the request being sent back is html?
Thanks!
Your code should look something like this,
respond_to do |format|
format.html index.html.erb
format.xml { render :xml => #organism.chromosomes) }
format.json { render :json => #organism.chromosomes) }
end
You just need
render :json => #organism.chromosomes
By looked at you edit, I think what you want is below:
console.log($.parseJSON("<%= raw #chromosomes %>"));
The problem ended up lying in the fact that Rails encoded the json data as a string, which is the default. To fix the issue I used
<%= #chromosomes.html_safe %>
on the front end. Further info about this can be found here:
Weird JSON Javascript problem in Rails
This should work, for Rails 2,
console.log($.parseJSON(<%= #chromosomes.dump %>));
for Rails 3,
console.log($.parseJSON(<%= #chromosomes.dump.html_safe %>));
String#dump escapes the characters and makes parseJSON() work. Notice that no quotation marks needed.

How do I handle response from an Ajax Request in Rails 3?

I have a CRUD application set up in Ruby on Rails 3 - its working as is. I need to add some ajax here. My first requirement is to retrieve a customised form when clicking on a New Form link. This is the link I have at this point:
<%= link_to 'New Book', new_book_path(:subject_id=>#subject.id), :remote=>true %>
For my controller I've made the following adjustment to the new book action:
def new
#book = Book.new
if params[:subject_id].to_i >0 then
#book.subject_id = params[:subject_id]
end
if request.xhr?
respond_to do |format|
format.html # new.html.erb
format.json { render json: #book }
render :layout => false, :file=>'app/views/books/_form'
return false
end
else
respond_to do |format|
format.html # new.html.erb
format.json { render json: #book }
end
end
end
I checked in firebug and clicking on the link generated returns the form html however I have no idea how to handle the response? Please do help.
Instead of responding with HTML respond with .js
Inside your .js.erb file could be something like this
$("#idname").append(<%= render "form" %>)
That way it renders and returns the form HTML but also gives the js code to append the HTML.
You can certainly rely on Rails generated JavaScript, but I always like to have "more control" over my JavaScript code. In e.g. jQuery you could have something like this (untested), if you want to insert the partial (html) rendered by your controller into the site:
$("#new-book-button").click( function () {
$.get('books/new', function(data) {
$('#some-form-container').html(data);
});
}

In Rails 3, how does one render HTML within a JSON response?

I'm porting an application from Merb 1.1 / 1.8.7 to Rails 3 (beta) / 1.9.1 that uses JSON responses containing HTML fragments, e.g., a JSON container specifying an update, on a user record, and the updated user row looks like . In Merb, since whatever a controller method returns is given to the client, one can put together a Hash, assign a rendered partial to one of the keys and return hash.to_json (though that certainly may not be the best way.) In Rails, it seems that to get data back to the client one must use render and render can only be called once, so rendering the hash to json won't work because of the partial render.
From reading around, it seems one could put that data into a JSON .erb view file, with <%= render partial %> in and render that. Is there a Rails-way of solving this problem (return JSON containing one or more HTML fragments) other than that?
In Merb:
controller:
only_provides :json
...
self.status = 204 # or appropriate if not async
return {
'action' => 'update',
'type' => 'user',
'id' => #user.id,
'html' => partial('user_row', format: :html, user: #user)
}.to_json
In Rails:
controller:
respond_to do |format|
format.json do
render template: '/json/message-1',
locals: {
action: 'update',
type: 'user',
id: #user.id,
partial: 'user_row.html.erb',
locals: { user: #user }
}
end
end
view: json/message-1.json.erb
{
"action": <%= raw action.to_json %>,
"type": <%= raw type.to_json %>,
"id": <%= raw id.to_json %>,
"html": <%= raw render(partial: partial, locals: locals).to_json %>
}
The closest to the original from Merb approach I could find in Rails is to use #render_to_string
render json: {
'action' => 'update',
'type' => 'user',
'id' => #user.id,
'html' => render_to_string(partial: 'user_row.html.erb', locals: { user: #user })
}
This gets around a fair bit of complexity that comes in from adding a layer of json.erb templates into the mix, whether it's Rails Purist approach I couldn't say; possibly something with RJS would typically be used.
There's another question that has more solutions for json.erb files. See json erb template cannot find other html partial
class UsersController < ApplicationController
respond_to :json
def show
#user = User.find(params[:id])
respond_with(#user) do |format|
if #user.save
format.json { render :json => #user }
else
format.json { render :json => #user.errors, :status => :unprocessable_entity }
end
end
end
end

How to return HTML directly from a Rails controller?

One of my model objects has a 'text' column that contains the full HTML of a web page.
I'd like to write a controller action that simply returns this HTML directly from the controller rather than passing it through the .erb templates like the rest of the actions on the controller.
My first thought was to pull this action into a new controller and make a custom .erb template with an empty layout, and just <%= modelObject.htmlContent %> in the template - but I wondered if there were a better way to do this in Rails.
In your controller respond_to block, you can use:
render :text => #model_object.html_content
or:
render :inline => "<%= #model_object.html_content %>"
So, something like:
def show
#model_object = ModelObject.find(params[:id])
respond_to do |format|
format.html { render :text => #model_object.html_content }
end
end
In latest Rails (4.1.x), at least, this is much simpler than the accepted answer:
def show
render html: '<div>html goes here</div>'.html_safe
end
Its works for me
def show
#model_object = ModelObject.find(params[:id])
respond_to do |format|
format.html { render :inline => "<%== #model_object['html'] %>" }
end
end

Resources