Ruby on Rails and Ajax - ruby-on-rails

I'm trying to learn ruby on rails and ajax. I've mostly worked through this tutorial: http://ruby.railstutorial.org/
and this: http://edgeguides.rubyonrails.org/working_with_javascript_in_rails.html
Now I'm trying to get the most basic things working so I have a foundation to build on. I would like to dynamically load content after the page loads.
I have a page that gets displayed with the following code in it (app/views/statc_pages/home):
<h1>StaticPages#home</h1>
<p>Find me in app/views/static_pages/home.html.erb</p>
<div name="results" id="results" class="results"></div>
And I have a file in app/assets/javascript/static_pages.js.coffee:
$(document).ready ->
$.ajax(url: "/static_pages/test").done (html) -> $('#results').append html
I have two files in app/views/static_pages/ which are test.js.erb and test.hmtl.erb with the same content. But it doesn't get added to the /home.
My static pages controller only has:
class StaticPagesController < ApplicationController
def home
end
def test
end
end
So far only the home page gets displayed. The coffeescript gets executed but the contents of /test won't get inserted. I'm not sure if the ajax code gets executed.
Edit: config/routes.rb:
AjaxTest::Application.routes.draw do
get "static_pages/home"
get "static_pages/test"
Edit:fixed the following previous edit:
Edit: When I change the ajax url to fetch to "test" i get:
Missing template static_pages/test, application/test with {:locale=>[:en], :formats=>[:js, :html], :handlers=>[:erb, :builder, :coffee]}. Searched in: * "/home/xyious/Programming/AjaxTest/app/views"
Edit: now chrome says that static_pages.js consists of the following:
(function() {
$(document).ready(function() {
return $.ajax({
url: "test"
}).done(function(html) {
return $('#results').append(html);
});
});
}).call(this);

It looks like you are missing the template (view file) for your StaticPages#test action.
Add a file called test.js.erb to your views/static_pages directory.

Are you using firebug javascript console (or chrome dev tools, etc) to debug? does the ajax request to /statis_pages/test execute? and try logging the html variable in the javascript after the request occurs
most likely you need to respond with js format
class StaticPagesController < ApplicationController
def home
end
def test
respond_to do |format|
format.js # should render app/views/static_pages/test.js.erb
end
end
end
checkout the rails casts for full details - http://railscasts.com/episodes/136-jquery-ajax-revised

The default dataType of jQuery's ajax is script. So basically you are send a js request to server asking for some html response.
For such case you need to change ajax to get directly, to send Ajax request as html dataType.
$.get(url: "/static_pages/test").done (html) -> $('#results').append html
Then in controller you need to set not to render layout for ajax request.
def test
if request.xhr?
render 'test', layout: false
return
else
# blah blah
end
end
But, to be frankly this type of requests are okay for experiments but too troublesome in real work.

Related

how to use a separate erb file for a controller free of application.erb rails

I am trying to use a different .erb file instead of default application.erb, I followed as its stated in https://guides.rubyonrails.org/layouts_and_rendering.html#finding-layouts
I have created a route in routes.rb as
get "/vue/v1/" => "vue#vue"
a controller as vue_controller.rb and its content is
class VueController < ApplicationController
layout "vue"
def vue
end
end
and in my view/layouts/, I also have created a file as vue.html.erb so that the controller can use it. The content of vue.html.erb is as simple as <%= javascript_pack_tag 'application' %> but whenever I go to "/vue/v1/", It only gave me error as
VueController#vue is missing a template for this request format and variant. request.formats: ["text/html"] request.variant: [] NOTE! For XHR/Ajax or API requests, this action would normally respond with 204 No Content: an empty white screen. Since you're loading it in a web browser, we assume that you expected to actually render a template, not nothing, so we're showing an error to be extra-clear. If you expect 204 No Content, carry on. That's what you'll get from an XHR or API request. Give it a shot.
what you are doing wrong is in your controller, you don't have a view for your vue action. Try adding a erb file in your views/vue

Rails Render Index with URL Parameters

At my work, we are in the middle of breaking up our Rails monolith. We are currently serving our react app through the asset pipeline. I am implementing JWT for authentication. I am trying to pass the token in the url without using sessions/cookies as part of an admin impersonating a user.
class ReactPagesController < ApplicationController
def index
render :index #this will open up the react app
end
end
Is it possible to render a view and pass along parameters in the url?
I want this to open up the index page with url parameter (i.e. localhost:4000/users?jwt=abc.def.ghi
I've tried doing something like render :index, jwt: abc.def.ghi, but that doesn't work. Is the only way to do this via redirect_to?
You are actually defining a redirection:
You want to go to localhost:4000/users
The page display the index page, and URL becomes localhost:4000/users?id=123
For the normal webpage, changing URL will make the browser redirect. As you can see the result when executing this JS in the Chrome Console:
window.location.href = "google.com"
the browser will redirect you to google.com
So, for a Rails's application, you should do a redirection by redirect_to to achieve the current needs.
However, if you really want to change the URL without redirection, you can do it via Javascript. Just use window.history to change your URL
Your controller:
# app/controllers/users_controller.rb
def index
#desired_id = 123
end
and your view
<%-# app/views/users/index.html.erb %>
<!-- rest of HTML -->
<script>
window.history.pushState("", "", "?id=<%= j #desired_id %>");
</script>
you can use redirect_to
redirect_to users_url, id: 5
will get you to /users?id=5
I don't think so, render is for rending the view and has nothing to do with the setting the url.
ruby docs

Can someone explain to me how ActionView templates work?

I'm not asking how to use them, I'm asking how do they work. My controller (just used one of the scaffold generators for my controller) has a method:
def index
#users = User.all
end
From that method, I can either get the html response (index.html.erb), even without specifying "html" in the request, or I can get a json response (index.json.jbuilder).
In other methods there's format.html and format.json. In the above example method index, there's no reference to either "type" of response. Why/how does it work?!?
Request for /users -- expected default html
Request for /users.html -- expected html response
Request for /users.js -- I get back the html content of <body> (maybe that's the partial?)
I do not have a template specified for .js anywhere.
Request for /users.txt -- I get the expected error message:
Missing template users/index, application/index with {:locale=>[:en], :formats=>[:text], :handlers=>[:erb, :builder, :raw, :ruby, :jbuilder]}.
Request for /users.xml -- I get the expected error message, even though xml seems more practical than a .js handler of a main resource:
Missing template users/index, application/index with {:locale=>[:en], :formats=>[:xml], :handlers=>[:erb, :builder, :raw, :ruby, :jbuilder]}
Why is a request for .abc even being processed at all? Even though it's not indicating that it's html, that's how it's processing it.
Started GET "/users.abc" ...
Processing by UsersController#index as
I see that there are :handlers specified, but none specify how/what should be handling the .js request. Why isn't the .js request spitting out an error? Hell, how is this all working without a respond_to block? I guess I expect the html handler by default, but I do not expect the .json response by default. There are often cases where I'd like all kinds of formats to be able to be returned, sometimes I'd prefer only to have a .json response over an html one. How/where do I find the documentation for dealing with this? It's not really related to the respond_to block, since even in the absence of respond_to, I'm getting multi format output.
In a controller, when no mime types are defined, rails will simply render the default one:
def index
#users = User.all
end
is equivalent to
respond_to :html
def index
#users = User.all
respond_with #users
end
This being said, let's take a look at other mime types:
Request for /users.js
This one is interesting, looking at the rails code base here we can see that it will render a template using default_render:
# to_js simply tries to render a template. If no template is found, raises the error.
def to_js
default_render
end
This is the default case for the html mime type also:
# HTML format does not render the resource, it always attempt to render a
# template.
#
def to_html
default_render
rescue ActionView::MissingTemplate => e
# ...
end
One does it means ? -- If a js template is defined, rails will render it. Otherwise, it will fallback to render the default html template. This is why you get the html content of <body>. Look your app/views/layouts/application.html.erb file:
<body>
<%= yield %>
</body>
Request for /users.txt and Request for /users.xml
Basically all "undefined by default" mime types will require you define some logic to not throw an exception. From rails source:
def respond
method = "to_#{format}"
respond_to?(method) ? send(method) : to_format
end
Rails define by default to_html and to_js. For other mime types, you will need to satisfy the conditions of the following method. For json and xml, it simply means calling to_json, to_xml or using respond_to.
For more information, take a look at the responder.rb file in rails source here. It's always good to look at rails source to really understand how things work. Of course sometimes it requires to spare some time and jumping around methods and files.
I'm not sure what would be the reaction of rails if a controller's method get request of, let's say, JS format while there's no "reposnd_to" block, but I think that it'd answer with error "unacceptible format". So I think that by default it assumes that request is of html format and to answer for other than html you have to point out with respond_to format block.
What about how the mechanism work, "rails determines the desired response format from the HTTP Accept header submitted by the client" (https://github.com/rails/rails/blob/master/actionpack/lib/action_controller/metal/mime_responds.rb#L85) rails sources says. So accepted formats is stated explicitly while generating request in mime-type

ajax get request for js (js.erb in rails) - url/naming problems

in my profile/index.html.haml,
I have
:javascript
$(document).ready(function(){
$('#clickablething').click(function() {
$.get('/profile', {**passed in json data**}, null, 'script');
})
});
which calls my index.js.erb when the click event occurs. However I'm wondering how I can rename the .js.erb file. Only /profile (or ./profile, or profile) works to call specifically index.js.erb. If I rename the file profile.js.erb it doesn't work (I've tried setting the url to profile.js, profile.js.erb, profile/profile.js and other variations, but those are all invalid requests as firebug shows.
Basically I would like to name index.js.erb profile.js.erb or something else, and am wondering how to refer to it in my get call.
Thanks!!
edit: This is really important for me now, since I have 2+ js.erb files I would like to call via ajax GET when different events happen. So I can't just stick to one index.js.erb. How do I do this? What's the ajax call for onescript.js.erb and anotherscript.js.erb?
Did you have correct route for /profile/profile.js?
resources :profiles
get :profile
end
After do that, you can try again.
The index action renders by default index.html.haml or index.js.erb, but you can tell it to render profile.js.erb if that is what you want...
Your get action has nothing to do with the file rails serves. Change your controller to something like this:
def index
respond_to do |format|
format.js { render 'profile/profile' }
end
end
I decided to put everything in index.js.erb and only run the sections i need conditionally...

When does "respond_to do |format|" make sense for Javascript?

I saw this code in a Rails controller:
respond_to do |format|
format.js {}
end
I've seen this for XML and HTML formats but not for Javascript.
Is this the way you specify a return format if you use for REST, like if you use replace_html or remote_form_for? I know RJS templates return compiled Javascript so I'm thinking maybe this is where this code might kick in.
If you put code inside the hash symbols(format.js {}), is that what gets send back as javascript to the browser?
It is used when an AJAX request is sent from the browser to a controller. The controller can respond with a script (which is generated by ruby statements in the view) which will be executed on the client.
Rails does a little magic on figuring out what 'template' to send out
in controller:
def foo
end
in view: (app/views/controller/) you can have
foo.html.erb (usual, html template)
foo.rjs (javascript template)
rails will send out the right template back to the browser, HTML for regular requets and RSJ for Ajax requests. You might want to put in javascript code like 'page.replace_html' ..etc in your RJS template. This way, you keep the controller clear of view code.
yuo can always just add the format to the url and see what it responds, /something.js would respond using the format.js code, if you want to use it, you can do the following to avoid rendering your entire layout:
format.js { render :layout => false, :text => #models.to_json }
that would respond with a json string
format.js { render :layout => false }
would require a template called [action].js.erb

Resources