My question is : do we need a view file for each action in our controller?
(like if we defined a say_hello action in a controller, is it necessary to add say_hello.html.erb in his view directory?
I'll edit this to say it depends (with same content). If you plan on using that controller action as JS or JSON you don't need a view file. if you want one to share in multiple views, the file can contain a shared partial (which can be used in other views). This examples is shown by the generators scaffolding create examples like this. They are helpful if you are learning rails. Not great otherwise.
If you were to share a partial, you could have a partial named _form.html.erb and then inside your say_hello.html.erb file, it would just call:
<%= render 'form' %>
If you want to render JSON or JS files you can respond_to in your action:
respond_to do |format|
format.html # say_hello.html.erb
format.json { render json: #hello } #no file needed
format.js { render js: #hello }
#format.js {} #do nothing... or use a little javascript in there...
# or have a file named say_hello.js.erb and use your #hello variable
end
Edit:
One last update. Your say_hello.js.erb file can do the anything on another view (if called remotely):
say_hello.js.erb
<% if #hello.attribute == "some value" %>
$('#div_in_another_view').show();
<% else %>
$('#div_in_somewhere_else').hide();
<% end %>
You can do jQuery and anything you want to the view calling it (as long as it's using AJAX).
End edit
Guides are great place to get started. Railscasts.com as well (even though Ryan isn't updating anymore).
Edit: A great example on the different options on the respond_to is on this rails guide regarding javascript
You can just pass javascript straight from that format.js call, or use a file if you need more complicated stuff. You don't need to do anything also. You could just have it return xml or nothing as well, depending on your use case.
No, it is not required. For example, you can render json or xml data from the controller without needed a view at all. This article explains it very well http://guides.rubyonrails.org/layouts_and_rendering.html
No you do not need a view for each action. BUT you do need a view for each action that will reach the end of the method.
If you return anywhere in the action then you are fine. A view is only required when an implicit render is called due to execution reaching the end of the action.
No, it's really up to you and it depends on what the action will actually do. Actions can render different types content types: text, json, html, xml... etc. Here's an example:
def show
render xml: #something
end
This action doesn't have a view, but it'll output an xml when called. It can also render different things based on the format of the call:
def show
respond_to do |format|
format.html do
redirect_to '/'
end
format.json do
render xml: #something
end
end
end
The action may also redirect (again, this one doesn't have a file):
def show
redirect_to '/'
end
At the end, it's really up to the programmer to handle how the action behaves, but if you leave it empty, it'll assume there's a file to render.
Related
as a Ruby newbie I am still getting to grips with the language. I have created a broadcast controller for a simple database that is already being used in production. However, I am getting the above mentioned error. Below is the code I have used:
show.html.erb
<p id="notice"><%= notice %></p>
<%= link_to 'Edit', edit_broadcast_path(#broadcast) %> |
<%= link_to 'Back', broadcasts_path %>
Index.html.erb
index.html.erb
broadcasts_controller.rb
boradcast controller
help controller
class HelpController < ApplicationController
skip_before_action :authenticate_user!
def about
#render text: "Hello"
end
end
I am not sure if I am missing any files or configs, I will add them in the comments if need be. Thanks
Incoming requests may use headers or parameters to indicate to Rails what format, called "MIME type", the response should have. For instance, a typical GET request from entering a URL into your browser will ask for an HTML (or default) response. Other types of common responses return JSON or XML.
In your case your "about" action does not have any explicit responders, and because of that Rails can't match the requested format (which is what the error message is trying to convey). You will probably just want to add an HTML template app/views/help/about.html.erb with your content. Rails should identify the HTML template and handle things from there.
More info
In Rails you need to respond with a specific format, and it is easy to setup your controller actions to handle a variety of formats.
Here is a snippet you might find in a controller which can respond in 3 different ways.
respond_to do |format|
format.html { render "foo" } # renders foo.html.erb
format.json { render json: #foo }
format.xml { render xml: #foo }
end
You can see more examples and deeper explanations in the documentation here.
ActiveRecord helps because it comes with serializers out of the box which can create JSON and XML representations of your objects.
I'm building a webapp that features a UI split into two sides, a menu bar and a content area.
The menu bar has a listing of the titles of all blogs that a user has written. When a title is clicked, the content area should change to show the posts of that blog.
1.) So on my menu bar, I have:
<%= link_to blog.title, blog, :remote=>true %>
And in my content area, I have:
<div id="contenthere"></div>
2.) So by my understanding, this should trigger the show method of the blog controller. There, I have the following in the method:
#blog = Blog.find(params[:id])
respond_to do |format|
format.js { render :show_blog }
end
3.) Which should go look for a file called show_blog.js.erb in views/blogs folder:
$("#contenthere").html("<%=escape_javascript(render :partial=>"show_blog")%>");
Which will take my div with commenthere id and render the _show_blog.html.erb partial (located in the blog view folder) with the blog parameter equal to the #blog parameter that was set in my blog controller.
4.) So my show blog partial has this code:
<%=#blog.title %>
<%=#blog.user_id %>
EDIT: Actually, I search around and found out that I can't use the method 'render' from within the assets folder-- where do I put the js.erb then? I've moved it to the blog view folder, home view folder (index.html.erb), and just the /view/ folder... The error is gone, but the link is not working...
EDIT: Put the show_blog.js.erb in my views/blogs folder, since it's the blog controller calling it. Nothing happening when I click the link and no JS errors shown in console. Is the js being called at all?
EDIT: Changed to reflect my final answer.
#blog = Blog.find(params[:id])
respond_to do |format|
format.js { render :show_blog }
end
That is not Rails default logic.
You didn't provided, how method is called, suppose
def show_blog
#blog = Blog.find(params[:id])
respond_to do |format|
format.js
end
end
Then, Rails will look for show_blog.js.erb in views/blogs and render that file.
Also, you need to pass actual instance to partial, because patrial is stand-alone chunk of code and doesn't know, what #blog is:
$("#contenthere").append("<%=j render :partial=>"show_blog", :locals=>{:#blog=>#blog}%>");
Very simple solution in the end--- The partial was calling for blog.title, blog.user_id, but #blog was the actual param that was passed. Just had to change to #blog.title and #blog.user_id.
I haven't been able to find any useful resources online on how to do this. Basically what I'm trying to do is run a simple jQuery $('#test-div').show(); when my def show_div controller action is complete.
I've tried the following and it doesn't work. It actually renders HTML which is confusing to me. when I explicitly state that the method respond with js.
users_controller.rb
def show_div
#user = User.first
respond_to do |format|
format.js {}
end
# also tried
# render :js => "$('#test-div').show();"
end
show_div.js.erb
$('#test-div').show();
render :text should do what you are asking for -- just return raw text (which in your case happens to be JavaScript code) without doing anything to it.
I am writing a Ruby on Rails application with a controller called "pages_controller" that is responsible for displaying pages to users. There are 3 different types of pages that can be displayed, and different things have to happen on the back end in each case, so I decided to break the functionality out into 3 methods within the controller. When the user requests a page, the "show" method is called, which figures out whether the page:
1. Belongs to the user
2. Belongs to another user, and can be viewed by the user requesting it
3. Belongs to another user, and cannot be viewed by the user requesting it (unauthorized)
The appropriate method is then called from there to display the page. The code looks something like this:
def show
if (something)
showMine
elsif (something else)
showAnother
else
showUnauthorized
end
end
def showUnauthorized
respond_to do |format|
format.html # showUnauthorized.html.erb
end
end
def showMine
respond_to do |format|
format.html # showMine.html.erb
end
end
def showAnother
respond_to do |format|
format.html # showAnother.html.erb
end
end
I am getting a template missing error because rails wants to render a view when "show" is called, but I do not want any views to be rendered when "show" is called. I simply want "show" to call the correct method from there, and the corresponding view for that method (showMine, showAnother, or showUnauthorized) to be rendered. How can I do this? Or am I going about this the wrong way entirely?
You need to declare these new actions that you have created in the routes file, as they don't belong to the RESTful routes.
I sugest to keep only the show action in your controller and create the IFs in the show view using the render method to include the partials(_showMine.html.erb, showAnother.html.erb, showUnauthorized)
example:
show view:
if (something)
<%= render 'showMine' %>
elsif (something else)
<%= render 'showAnother' %>
else
<%= render 'showUnauthorized' %>
end
I hope it helps...
I basically agree with Samy's comment, but here's some background:
The method that tells Rails what view to use is render. If there's no call to that method in your show method, Rails assumes you have a view called show.xxx.xxx, e.g. show.html.erb, that is supposed to be rendered. Note that it doesn't assume template will be prefixed with show because that's the name of the method. It assumes it will be show because that's the name of the action. The name of the action is passed to the controller as part of the request; it's not simply derived from the name of whatever method has a respond_to block in it.
All the respond_to blocks do is specify different view templates based on the MIME type of the request, but since you never call render, all of those extra methods are still trying to call the show view (show.html.erb in every case), because you never told Rails to render any other view, and the action name is show.
So, instead of the respond_to blocks, just call render [some_view] in each of your other methods.
This might not be the clearest answer, but I'd suggest also reading the following:
http://ryanbigg.com/2009/04/how-rails-works-2-mime-types-respond_to/
It describes what respond_to does, in particular how it keys off the action name to determine what view to render.
So there's the basic function like this ....
def show
#position = Position.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #position }
end
end
and if you go to, say, http://localhost/(position_id).xml then you will see the xml... But I wish to have a standard xml filename that I can write the object details to because I want to access it from outside rails. I am very new to rails and have not programmed in a while...seems like this should be easy, right ? So I just want to have a file created with a name like my_xml.xml for all the objects, rather than 1.xml, 2.xml, (id).xml, etc.
Thanks for the help !
I met similar questions, here is my solution(I am a newbie):
I added below in routes.rb:
resources do
collection do
get 'my_xml'
end
end
Then added the my_xml action in controller. In my_xml action, assemble all data, and format it to xml via to_xml method.
No sure whether above is useful for you. Hope it helpful.