I'm trying to simply render a view using UJS and Rails 3, but it's not actually working. I've read many tutorials but can't seem to get this. Here are some code snippets:
index.js.erb
"<%= render user_path(#this_user) %>"
index.html
<%= form_tag users_path, :method => :get, :remote => true do %>
<%= submit_tag "Test", :name => nil, :class => "btn" %>
<% end %>
users_controller.rb
def index
#users = User.all
#this_user = User.find(1)
respond_to do |format|
format.html # index.html.erb
format.js
format.json { render json: #users }
end
end
Every time I click on "Test", I get the following output:
Started GET "/users?utf8=%E2%9C%93" for 127.0.0.1 at 2012-10-19
11:31:49 -0700 Processing by UsersController#index as JS Parameters:
{"utf8"=>"✓"} User Load (0.4ms) SELECT "users".* FROM "users"
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" =
$1 LIMIT 1 [["id", 1]] Rendered users/index.js.erb (1.8ms)
Completed 500 Internal Server Error in 6ms
ActionView::Template::Error (The partial name (/users/1) is not a
valid Ruby identifier; make sure your partial name starts with a
letter or underscore, and is followed by any combinations of letters,
numbers, or underscores.):
1: "<%= render user_path(#this_user) %>" app/views/users/index.js.erb:1:in
_app_views_users_index_js_erb__2145063269526192522_70203075823780'
app/controllers/users_controller.rb:9:inindex'
It appears it's looking for a partial; however I just want it to execute the view associated with the "show" action on the User controller. So a completely new page.
What am I doing wrong? First step is to render a completely new view, but I plan to render a partial view within the "show" page after I figure this out.
Thanks in advance for any help!
Look at index.js.erb:
<%= render user_path(#this_user) %>
That is telling Rails to render a partial with the name of the value of user_path(#this_user).
You view file index.js.erb needs to return JavaScript. So, the following would work:
alert('The Id of this User Object is: <%= #this_user.id %>');
In the future, you can render a partial (that contains JavaScript code) by doing the following:
$("#popup").html("<%= escape_javascript(render(:partial => 'show_sold_out_popup') %>");
Related
Background (changed after correspondance with #TomLord):
I am building a simple site with only a index page and no subpages. The index page has a "search" field that takes input (id) and sends a GET request to a RESTful API running in the background. The response from the API is JSON {"market price": "4306057.0", "retail price": "4995000.0"}.
I want to display this result on the index page, together with the search field. However, when I press the button the result is not displayed anywhere.
Code:
index.html.erb
<section id="search">
<div class="container">
<%= form_tag({controller: "model_request", action: "result"}, method: "get", remote: true) do %>
<%= label_tag(:q, "Search for") %>
<%= text_field_tag(:q, "913384637") %>
<%= submit_tag("Get the price!") %>
<% end %>
</div>
</section>
<section id="display_result">
<div class="container">
</div>
</section>
And the modelrequest_controller.rb looks like this:
class ModelrequestController < ApplicationController
def result
id = params['q'].capitalize
response = RestClient::Request.execute(
method: :get,
url: "http://0.0.0.0:80/?id=#{id}")
#result = JSON.parse response
respond_to do |format|
format.js {render layout: false}
end
end
end
My routes.rb
Rails.application.routes.draw do
root 'index#index'
match "/modelrequest", to: "modelrequest#result", via: 'get'
end
The javascript for results looks like this:
result.js.erb
$("#display_result").html("<%= escape_javascript(render partial: 'modelrequest/result', locals: { result: #result } ) %>");
And the simple _result.html.erb for displaying the partial is
<div id="display_result">
<%= #result %>
</div>
Output:
Started GET "/model_request?utf8=%E2%9C%93&q=913384637&commit=Get%20the%20price!" for 127.0.0.1 at 2018-12-19 20:55:33 +0100
Processing by ModelRequestController#result as JS
Parameters: {"utf8"=>"✓", "q"=>"913384637", "commit"=>"Get the price!"}
Rendering model_request/result.js.erb
Rendered model_request/_result.html.erb (0.8ms)
Rendered model_request/result.js.erb (6.8ms)
Completed 200 OK in 383ms (Views: 11.6ms | ActiveRecord: 0.0ms)
In a "normal" rails site, a search form works as follows -
You define a form in the view. This will, by default, POST data to an endpoint - but you can also do this via a GET request. In your case, you originally chose:
form_tag("/search", method: "get")
This will send the form data to GET /search, synchronously, and therefore perform a full page reload.
This is a perfectly valid thing to do. However, you wanted to remain on the index page - therefore the request needs to be asynchronous:
form_tag("/search", method: "get", remote: true)
...But now, that endpoint needs to do something different. Instead of rendering a new page, it needs to partially update the current page.
The standard approach for this in a rails application is to do something along the lines of:
# In the controller action, e.g. SearchController
def show
#results = # ...
respond_to do |format|
format.js {render layout: false}
end
end
# In the view, e.g. `search/show.js.erb`
$("#display_result").html("<%= escape_javascript(render partial: 'results', locals: { results: #results } ) %>");
# In an HTML partial, e.g. `search/_results.html.erb`
<% results.each do %>
...
The key idea is that on your main page (index.html.erb?), you must have a container to display the results. Then, rather than rendering a new page, you are merely rendering an HTML update inside that container.
This is, of course, not the only way of doing it. Modern websites will often instead fetch JSON data for a search result and then determine how to display that via JavaScript.
However, the above approach is the most "minimal" change from your current design - without needing to add additional design patterns, you can leave most of your existing haml/erb templates as-is, and just add a little code to render the results as a partial.
I'm trying to display errors messages in my ajax form (the code is based on this question):
posts_controller.rb:
def create
#post = current_user.posts.build(params[:post])
if params[:commit] == "Publish"
#post.status = "Published"
elsif params[:commit] == "Save Draft"
#post.status = "Draft"
end
respond_to do |format|
format.html do
if #post.save && #post.status == "Published"
flash[:success] = "Post published"
redirect_to #post
elsif #post.save && #post.status == "Draft"
flash[:success] = "Post saved as draft"
render 'edit'
else
render 'new'
end
end
format.js do
#post.save
end
end
end
posts/create.js.erb:
<% if #post.errors.any? %>
alert('There are errors.');
<%= render :partial=>'js_errors', :locals=> { :target=> #post } %>
<% else %>
$('.busy').html('Saved.');
<% end %>
js_errors.js.erb:
<% target.errors.full_messages.each do |error| %>
$('.busy').append('<p><%= escape_javascript( error ) %></p>');
<% end %>
posts/new.html.erb:
<%= form_for(#post, remote: true, :html => { :multipart => true }) do |f| %>
<%= render 'fields', f: f %>
<div class="form-actions">
<%= f.submit "Publish", class: "publish btn btn-primary pull-left" %>
<%= f.submit "Save Draft", class: "save-draft btn btn-default pull-left" %>
<div class="busy pull-left">
</div>
</div>
<% end %>
But for some reason nothing displays (.busy always remain empty).
In the console I can see that js_errors.js.erb is being displayed:
Started POST "/posts" for 127.0.0.1 at 2013-01-04 18:02:18 +0800
Processing by PostsController#create as JS Parameters: {"utf8"=>"✓",
"authenticity_token"=>"Qfn6HsPPDxyB1t4bM/OQKPbJ/aoAMkp74y0Z6xkoXCY=",
"post"=>{"title"=>"", "content"=>"", "tag_list"=>""},
"_wysihtml5_mode"=>"1", "commit"=>"Save Draft"} User Load (0.7ms)
SELECT "users".* FROM "users" WHERE "users"."remember_token" =
'ljl0ZsuoiHg0Jilz8bgy-g' LIMIT 1 (0.2ms) begin transaction
(0.2ms) rollback transaction Rendered posts/_js_errors.js.erb
(3.8ms) Rendered posts/create.js.erb (7.5ms) Completed 200 OK in
25ms (Views: 11.2ms | ActiveRecord: 1.0ms | Solr: 0.0ms)
What could be the problem?
(I do see the validation messages if I remove remote:true from the form).
EDIT:
I noticed alert('There are errors.'); is not being triggered. Strange.
It looks like a naming problem. You're asking to render the partial js_errors, which would be called _js_errors.js.erb; but you say your file is actually called js_errors.js.erb (no leading underscore).
Try adding the underscore and see if that helps matters.
I have been facing a similar problem a few days ago. I used remote => true option in my form to use Ajax in my Rails 3 application. After that, I have been looking for solution for validating my form fields. After trying a good number of jQuery / Javascript approaches (none of them worked for me though) I came to know about a superb gem called client_side_validations. It is very easy to install by following the instructions on github link (https://github.com/bcardarella/client_side_validations). It works like charm for client side validation of form fields, an awesome gem indeed. Hope this helps with people who are tired of looking for a simple solution for client side validation of model fields after using Ajax in Rails 3 application.
I'm a newbye that is trying to do little things in Rails, at the moment I have created an app that build some links and I want to refresh the content of a Div when they are clicked.
In my application.html.erb I have the layout with the next head:
<%= stylesheet_link_tag "application" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
(I have read about change the second line for :defaults but if do that I get a 404 error defauls.js)
I have an index.html.erb that render a partial with this:
<%= render :partial => 'masvisitadas' %>
In my _masvisitadas.html.erb I have the code that generate the links:
<%= link_to solution.SolutionName, "/soluciones/despliega/" + solution.Id.to_s, :remote=>true %>
This generate the next html:
http://localhost:3000/soluciones/despliega/501D0000000QWp6IAG
In my controller I have the next def:
def despliega
respond_to do |format|
format.js {}
end
end
Finally I have created despliega.js.erb:
jQuery(function($) {
var html = "<%= escape_javascript(render('despliega')) %>";
$("#customTopLeft").prepend(html)
$("customTopLeft").html("<%= escape_javascript(render(:partial => 'despliega')) %>");
});
In the log of the web server when i click a link it seems all going well:
Started GET "/soluciones/despliega/501D0000000QXM0IAO" for 127.0.0.1 at 2012-08-
20 12:16:53 +0200
Processing by SolucionesController#despliega as JS
Parameters: {"id"=>"501D0000000QXM0IAO"}
Rendered soluciones/_despliega.html.erb (0.0ms)
Rendered soluciones/_despliega.html.erb (0.0ms)
Rendered soluciones/despliega.js.erb (15.6ms)
Completed 200 OK in 31ms (Views: 31.3ms | ActiveRecord: 0.0ms)
And in the firebug I can see the call with any error but nothing happends.
This is killing my head :) Thanks in advance for any help here.
Regards.
What's in _despliega.html.erb?
Try changing despliega.js.erb to this (and only this):
$('#customTopLeft').html("<%= escape_javascript(render :partial => 'despliega') %>");
Edit - oh, and make sure you have the jQuery libraries included ..
Hi I've set set of an appreciation controller that handles user's liking different posts. Each post has a like button and when I click it looks like the request goes through but the page doesn't refresh and update the button.
When I click like this is the log, it shows the unlike partial being returned but nothing changes:
Started POST "/appreciations" for 127.0.0.1 at 2011-04-22 05:47:28 -0700
Processing by AppreciationsController#create as JS
Parameters: {"utf8"=>"✓", "authenticity_token"=>"zQQJeXZiAPFeQ/7AEy9hvQac01+jq929XUXHrd6eSOE=", "appreciation"=>{"liked_id"=>"3"}, "commit"=>"Like"}
User Load (1.1ms) SELECT "users".* FROM "users" WHERE ("users"."id" = 4) LIMIT 1
Post Load (0.4ms) SELECT "posts".* FROM "posts" WHERE ("posts"."id" = 3) ORDER BY posts.created_at DESC LIMIT 1
SQL (0.5ms) INSERT INTO "appreciations" ("created_at", "liked_id", "liker_id", "updated_at") VALUES ('2011-04-22 12:47:28.642264', 3, 4, '2011-04-22 12:47:28.642264')
Redirected to http://localhost:3000/posts/3
Completed 302 Found in 185ms
Started GET "/posts/3" for 127.0.0.1 at 2011-04-22 05:47:28 -0700
Processing by PostsController#show as HTML
Parameters: {"id"=>"3"}
Post Load (0.4ms) SELECT "posts".* FROM "posts" WHERE ("posts"."id" = 3) ORDER BY posts.created_at DESC LIMIT 1
User Load (1.2ms) SELECT "users".* FROM "users" WHERE ("users"."id" = 4) LIMIT 1
Appreciation Load (0.3ms) SELECT "appreciations".* FROM "appreciations" WHERE ("appreciations".liker_id = 4) AND ("appreciations"."liked_id" = 3) LIMIT 1
CACHE (0.0ms) SELECT "appreciations".* FROM "appreciations" WHERE ("appreciations".liker_id = 4) AND ("appreciations"."liked_id" = 3) LIMIT 1
Rendered posts/_unlike.html.erb (49.4ms)
Rendered users/_like_form.html.erb (77.7ms)
Rendered posts/show.html.erb within layouts/application (208.9ms)
Completed 200 OK in 248ms (Views: 212.4ms | ActiveRecord: 5.2m
appreciations controller
class AppreciationsController < ApplicationController
before_filter :authenticate_user!
def create
#post = Post.find(params[:appreciation][:liked_id])
current_user.like!(#post)
redirect_to #post
end
def destroy
#post = Appreciation.find(params[:id]).liked
current_user.unlike!(#post)
redirect_to #post
end
end
_like_form.html.erb
<% unless current_user?(#user) %>
<div id="like_form">
<% if current_user.likes?(#post) %>
<%= render 'posts/unlike' %>
<% else %>
<%= render 'posts/like' %>
<% end %>
</div>
<% end %>
_like.html.erb
<%= form_for(current_user.appreciations.
build(:liked_id => #post.id),
:remote => true) do |f| %>
<div><%= f.hidden_field :liked_id %></div>
<div class="actions"><%= f.submit "Like" %></div>
<% end %>
_unlike.html.erb
<%= form_for(current_user.appreciations.find_by_liked_id(#post),
:html => { :method => :delete },
:remote => true) do |f| %>
<div class="actions"><%= f.submit "Unlike" %></div>
<% end %>
Should the result of POST "/appreciations" be a redirect to http://localhost:3000/posts/3? You're using the :remote => true option of the form so I believe you need to change your controller to this:
respond_to do |format|
format.html { redirect_to #post}
format.js
end
And create a *.js.erb partial that does something like this:
<% unless current_user?(#user) %>
<% if current_user.likes?(#post) %>
$("#post_form").html("<%= escape_javascript(render('posts/unlike'))%>");>
<% else %>
$("#post_form").html("<%= escape_javascript(render('posts/like'))%>");
<% end %>
<% end %>
Basically I believe you're seeing no change because you're making an AJAX POST, but not doing anything with the result. You would need JavaScript that updates the innerHTML of a DOM element with the result of your post.
This post might be helpful: http://www.stjhimy.com/posts/7-creating-a-100-ajax-crud-using-rails-3-and-unobtrusive-javascript
Here is my index.html.erb:
<%= render :action => 'new' %>
<% unless #posts.empty? %>
<%= render #posts %>
<% end %>
The posts are displaying, but nothing in the new page is.
It's not in the log either:
Processing PostsController#index (for 127.0.0.1 at 2010-07-27 20:54:28) [GET]
Post Load (0.2ms) SELECT * FROM "posts"
Rendering template within layouts/application
Rendering posts/index
Rendered posts/_post (8.4ms)
Also, if I replace it with just <%= render :new %>, I get the error:
undefined method `include?' for :new:Symbol
But it should allow me to render the action implicitly with Rails 2.3.8.
I would be grateful if anyone could explain either of these things.
You should only render partials within a view. Since you need the contents in multiple views, you can convert the contents of new.html.erb to a partial (say, _new.html.erb) and then
<%= render 'new' %>
From new.html.erb as well as index.html.erb. render :action => 'actionname' is meant for rendering another action's template from within the controller.
Note that its a common idiom to create a _form.html.erb partial for each model, and use that whenever you need to be able to add or edit a model instance from elsewhere. That would be useful in this case as well. You would then render the form partial from index, new and edit.
Just a thought, but I suspect that erb will treat those two blocks as a single line. As you probably know, in Ruby it's quite idiomatic to put an "unless" or "if" condition at the end of a line.
You may want to add a line break before "unless" but after <%.