I have a Controller named ProductsController. In that controller are several actions such as socks and towels. I also have views of socks and towels. The view pages of socks and towels have the exact same form inside it. I'm going to use ajax in both files for the forms. Since the form is the exact same in both views, I see it pointless to create multiple ajax js files for the actions to call when ajax is called. How can I have both actions socks and towels call the same js.erb file instead of socks.js.erb and towels.js.erb respectively?
My controller and the action socks.
def socks
#socks = Socks.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #socks }
#ok, I get the line below is needed for ajax. Is there something I could add for
#the action not to call socks.js.erb and instead a different file, say ajax.js.erb
format.js
end
end
I think you're looking for render here. Using it you can render a template/view of another action. See the doc: Layouts and Rendering.
render 'products/show'
render :template => 'products/show'
render "/u/apps/warehouse_app/current/app/views/products/show"
as Sergio rightly said, you can do exactly that using the render command. Basically, in both socks and towels actions, you can render a common ajax.js.erb file when the respond_to is for JS.
I am adding this answer however because of your comment. It seems that your socks and towels methods as well as the forms and associated responses are very similar. If that is the case, why not use a single action for the same? Basically, you can use a URL parameter to specify the nature of product in the ProductsController actions.
So you would have something like:
def ProductsController
def index
if params[:nature] == "socks"
#socks = Sock.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #socks }
format.js
end
elsif params[:nature] == "towels"
#towels = Towel.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #towels }
format.js
end
end
end
end
Now you would need 2 view files index.html.erb and index.js.erb and there you can check the params value again and display the relevant collection.
This is not an ideal solution, but more a quick fix.
Failing that, you can also define a new action method in the ProductsController and have both forms point to that.
Related
I'm making a Single Page Application with Ruby on Rails (it's my first ruby project ever so I'm definitely missing a lot of stuff yet).
So I have a side menu with some links and the right part of the page is supposed to hold a container which is meant to be filled with some content of partial pages.
The typical menu link I have now looks this way:
<%= link_to t('my-groups'), :controller => 'dashboard', :action => 'mygroups', :remote => true %>
I have a dashboard controller, here's the simplified version of it
class DashboardController < ApplicationController
def mygroups
respond_to do |format|
format.js
end
end
I have a dashboard template with the container div in it
<div class="right_col" role="main">
<h2>This is the default content of center page</h2>
</div>
And here's the routes.rb path for it:
get 'dashboard/mygroups' => 'dashboard#mygroups'
I also have one partial page alogside with my dashboard template and it's called _mygroups.html.erb and a javascript file mygroups.js.erb which is called as my controller action
look at the screenshot of the structure
The contents of this js.erb file are:
$('.right_col').html("<%= escape_javascript(render(:partial => 'mygroups')) %>");
It all works and the partial contents appear inside the container on link click just fine.
But there are still 2 problems I couldn't google the answer for
The questions part:
1) It works with Ajax call but if I simply put this http://localhost:3000/dashboard/mygroups to my browser's navigation line and hit enter, it will give me this error
ActionController::UnknownFormat in DashboardController#mygroups
ActionController::UnknownFormat
Extracted source (around line #70):
def mygroups
respond_to do |format|
format.js end end
How can I avoid this and just redirect to index in this case?
I understand that ajax uses POST, but I tried to use post instead of get in routes.rb for this action, and it didn't work at all
2) What if I have a lot of actions for different partial pages, do I have to create a new js.erb file for each action? Can't it be done in some simplier way with just one file?
3) Is it possible to not specify controller and action on this link explicitly?
<%= link_to t('my-groups'), :controller => 'dashboard', :action => 'mygroups', :remote => true %>
I mean since it's supposed to be a POST ajax request, how come I need to display the url like this http://localhost:3000/dashboard/mygroups to a user?
Add format.html in controller like:
class DashboardController < ApplicationController
def mygroups
if request.xhr?
respond_to do |format|
format.js
end
else
redirect_to root_url
end
end
you can add url in link_to tag like:
<%= link_to t('my-groups'), '/dashboard/mygroups', :remote => true %>
Answers to you questions
When you hit the URL in browser, it sends vanilla HTTP get request(non-ajax) which your controller action is not configured to handle it. You need to add format.html and template named groups.html.erb where generally you will list all the groups, I guess.
respond_to do |format|
format.html
format.js
end
Ideally you have to create separate file for each action but if you can take something common out of different action then you can move common template code to a partial and render it either in a separate template having something special or from the controller action directly.
Yes. The rails way is to use routes helper. Run rake routes to list all available routes in your app and find relevant helpers.
I would strongly suggest to read the rails guide to understand how everything works.
In a create method in controller I have the following code:
respond_to do |format|
format.js { render json: { html: render_to_string(partial: '/users/photos/card', object: #photo, as: 'photo') } }
end
which works perfectly. Now I would like to move this in create.js.erb to have the possibility to execute additions js. However I do not figure out how to render the json above in create.js.erb.
Any idea how to accomplish this. Thanks in advance!
If I understood you right, what you are trying to achieve is to be able to access your JSON inside a js.erb view. In order to accomplish that, what I've done in the past is the following:
In your create.js.erb:
var yourJSON = JSON.parse("<%= raw(j render :partial => '/users/photos/card', object: #photo, as: 'photo') %>");
And in your controller:
respond_to do |format|
format.js # This will render the create.js.erb
format.json { render :partial => '/users/photos/card' } # Leave this one in case you also want to be able to respond to this format i.e: "http://localhost:3000/users/photos/card/id.json"
end
Hope this helps!
P.S: Let me know if you were trying to achieve something different.
I work on a task manager app, and I want to create html div 'cards' (with title, duration etc...), with all the datas I got on a database in rails.
I guess that I have to use javascript functions, but I can't get a way to do it.
I saw a lot of things on google, but I can't find exactly javascript calls from a rails controller (because I only catch all datas in the controller).
Here is my controller :
def new
# Retrieve all tasks in the project
#taskModel = Task.new()
#projectTasks = #taskModel.getProjectTasks()
# Add tasks on html
(0..#projectTasks.length).each do |i|
respond_to do |format|
format.js { render :js => "window.createTask();" } # I need to pass parameters in the createTask function
end
end
end
and my js file :
window.createTask = (title, content, duration) ->
card = document.createElement('div');
document.getElementsByClassName('content')[0].appendChild(card);
With my code, I get this error : ActionController::UnknownFormat
ActionController::UnknownFormat indicated that your ajax request is interpreted as a request with the wrong format. To answer this part better you'd have to post the javascript with the ajax call.
Secondly, you have to rethink the render in this block
(0..#projectTasks.length).each do |i|
respond_to do |format|
format.js { render :js => "window.createTask();" } # I need to pass parameters in the createTask function
end
end
You are calling respond_to multiple times which is just wrong. Put this loop into a new.js.erb view.
I have a scaffold called post which has a title and a description. On my layout I have a link to create a new post that has :remote => true. How would I make it when I click on that remote link to change the content of a div so that I can create a new post?
Let's suppose the action you will use is called new.
You should create a file called new.js.erb into views/posts that will be rendered when you post remotely your form. That file must include the javascript that places the new post into the div you want to fill. As an example, it could contain
# new.js.erb
$('div#container').html("<p><%= escape_javascript(#post.title) %></p>").append("<p><%= escape_javascript(#post.content) %></p>");
The javascript will be executed immediately after the ajax post is finished and the new post is created. Remember the following:
- You have to include jQuery
- You have to specify in posts_controller the ability to render .js format, something like
# posts_controller.erb
def create
#post = Post.new(params[:post])
respond_to do |format|
if #post.save
format.html { redirect_to(#post, :notice => 'Post created via non AJAX.') }
format.js # the actual ajax call
else
format.html { render :action => "new" }
end
end
end
I have a comments controller with index and create actions among others. Both those actions respond to html and js format.
Whenever I got create request via ajax, I would like to add new comment and then redirect to index.js, so the comments on screen are updated without reloading the page.
This sort of thing works flawlesly in Chrome. But whenever I try this in Firefox or IE, it turns out, that the redirect from create.js lands in index.html...
Even when i force the redirect to be js:
redirect_to polymorphic_path([#commentable, :comments]), :format => 'js'
It land up in the format.html in Firefox and IE.
Any idea what might be happening here?
There are various issues with the way browsers handle 302 requests differently. Some lose request types, others lose request method (an example ticket: http://trac.tools.ietf.org/wg/httpbis/trac/ticket/160).
I would suggest that rather than redirecting to a new URL when using JS, you simply render the same action. So something like this:
class CommentsController < ApplicationController
def index
setup_for_index
respond_to :html, :js
end
def create
# Creation stuff...
respond_to do |format|
format.html {redirect_to :action => :index}
format.js do
setup_for_index
render :action => :index
end
end
end
private
def setup_for_index
#comments = ...
end
end