Render view from another view : controller not called - ruby-on-rails

I'm developing a litte blog like application and at the moment I'm facing a problem that I can't resolve.
I have 2 models at the moment :
1. Post
2. Comment
I can already manage my posts without difficulties but I have some problems with comments. I chose to make a relation has_many / belongs_to between my post and my comment models. I'd like to display all the comments related to a post when the user is on the post's page. My erb looks like this :
#some code
#...
#...
#render the comments
<%= render :template => "comments/index", :locals => {:post_id => #post.id} %>
My problem here is that the method index from my CommentsController is never called. I put some puts in the index method and they are never displayed in the console.
Should I use another tag to render the view ? Is there another way to do this ?
Thanks in advance for your help.

If the post view is the only page to show comments, you don't have to call comments/index to get comments, just show comments when rendering the post view, for example
In your post view
#some code
#...
# render comments
<% #post.comments.each do |c| %>
<%= c.content%>
# ...
<% end %>
Or put them in a partial with a post parameter if comments are used in many views
In app/views/partials/_comments.html.erb
# render comments
<% post.comments.each do |c| %>
<%= c.content%>
# ...
<% end %>
and render this partial where you want to show comments:
#some code
#...
# render comments
<%= render partial: "partials/comments", locals: { post: #post } %>
Using comments/index to get comments and showing them in a view is more likely the frondend tech such as Javascript/AJAX to load page parts dynamically. In this case, the comments/index is more likely an API call(render a JSON format instead of a html view).

Related

How to display all posts with all its comments - Ruby on Rails

I'm new to rails and don't know how to achieve this in rails. It might be a really stupid question. But it was not covered in the RoR Codecademy course I did and could not fint a answer elsewhere.
So I have two tables, posts and comments that have an one-to-many relationship. One post has many comments.
I want to display all post with all its comments underneath. What would be the correct way to do this?
There are two ways to do this:
First: you can do like this way in your post controller action (suppose :index) do:
def index
#posts = Post.all
end
And in your index.html.erb
<% #posts.each do |post|%>
# Your post attribute like name etc
<% post.comments.each do |comment|%>
# Your post attribute like name etc
<% end %>
<% end %>
Second: in your post controller action do:
def index
#posts = Post.all.includes(:comments)
end
And in your index.html.erb
<% #posts.each do |post|%>
# Your post attribute like name etc
<% post.comments.each do |comment|%>
# Your post attribute like name etc
<% end %>
<% end %>
Difference in above two ways is that in first one there is always a data base call when you do "post.comments" but in second there is only two data base call i.e. "Post.all.includes(:comments)", no data base call at view part, so it is up to you which way you want to use.
If a Post has_many comments then:
post = Post.find(1)
post.comments.each do |comment|
# do something with each comment here
end

Getting 'form_for(#something)' to work outside of new.html.erb

I want to place my <%= form_for(#something) do |f| %> which is currently located in app/views/something/new.html -- inside multiple pages, so maybe in app/views/layouts/application.html.erb
How do I get the #something variable and the form to work properly there, or somewhere else -- since it's defined in the controller #new action of SomethingController, it only seems to be available in the appropriate new.html.erb view..
You can put the form anywhere, just provide an instance variable of #something in controller
The basic usage is here.
ThisThingsController
def show
#this_thing = foo
#that_thing = bar
end
end
# View
<%= #this_thing %>
<%= form_for #that_thing %>
Of course you can use partial to render the form, as long as you feed it with variable it needs.
Try
<%= form_for SomeThing.new do |f| %>
Without fully understanding what you are trying to accomplish, I'll make this suggestion.
Add a before filter to your ApplicationController (alternatively you could create a module and mix it in where needed). Then call the before_filter when needed. This example will always run the before filter:
class ApplicationController
before_filter :set_something
private
def set_something
#something = ... # Fill in the logic here
end
end
Then add your form where needed. You can even make it appear conditionally depending on whether #something is set.
<% if #something %>
# Form goes here
<% end %>

What to render on error in a Rails controller

In my rails application, I've got a partial view with an entry form on it. The form gets included on multiple pages across my app. The form in the partial posts to a RidesController to save with a create method like this:
RidesController.rb
def create
#ride = current_user.rides.build(params[:ride])
if #ride.save
flash[:success] = "Ride created!"
redirect_to root_path
else
#rides = current_user.rides.paginate(:page => params[:page])
render 'pages/home' # <---- WHAT GOES HERE?
end
end
I've commented the line where my question is. When we have an error, I need to present the same view that the user is presently on. But because this controller is being invoked from a partial instead of a full view, I don't know how to tell what context it's coming from.
Right now if there's an error on /rides/new, the user ends up redirected to the homepage which also has the form.
One way you could do this is pass the template path in with the form.
Add this to each main view that includes the form partial (e.g. pages/home, rides/new, etc):
<% #current_page_template = __FILE__ %>
In your form partial:
<%= form_for ... do |f| %>
<%= hidden_field_tag 'current_page_template',
#current_page_template.sub(File.join(Rails.root, 'app', 'views'), '') %>
In your controller:
def create
...
if #ride.save
...
else
...
render params[:current_page_template]
end
end

Where does the site-wide footer logic belong in a Rails 3 app?

I have a site-wide footer that should display a list of recent Users and Posts. I'm wondering where the logic should to gets this data. Should I have a "recent_users" method in the UsersController and a "recent_posts" method in the PostsController, or should I have a separate FooterController?
How about a _recent_users partial views/users and a _recent_posts partial in views/posts and have the footer partial render both of them?
All "business logic" should be put in the Model, not the controller. The query for recent Users and Posts should be in the User and Post model. Then, if you have a site-wide view element, move it into a partial and add that partial into the application.html.erb.
# User.rb
model User
def recent
# logic and query here
end
end
# Post.rb
(see above)
# application_controller.rb
before_filter :get_recent_posts
before_filter :get_recent_users
...
private
def get_recent_posts
#recent_posts = Post.recent
end
def get_recent_users
#recent_users = User.recent
end
# application.html.erb
...
<%= yield %>
...
<%= render :partial => 'layouts/footer', :locals => { :recent_users => #recent_users, :recent_posts => #recent_posts } %>
# layouts/_footer.html.erb
<% recent_users.each do |user| %>
<%= link_to user.name, user %>
<% end %>
# same for posts
A few important things to note:
don't access the instance variables (the #foo) in the partial... pass it into the locals hash and access it as a variable instead. It's just generally bad practice
you could also use a module
look into caching because you probably don't want to hit your database TWICE on every page load. You could use fragment caching on the footer and expire it every 15 minutes (probably the best option).

Rails show views from a different controller

In my Ruby on Rails application
I have a page Aboutus - This has a Controller and View. Has no model.
I have a Comments model (generated by the rails generate scaffold comment) - This has a Controller, view, model
On my Aboutus page, I want to show the "Comments" from the comments model, so I am thinking of using the Comments index action (to list comments) and new action (to create new comments) on my Aboutus page.
I am having trouble getting this right.
This is what I did:
Aboutus controller, I added
redirect_to :controller => "comments", :action => "index"
Aboutus views, I added
<%= render 'comments/index' %>
It doesnt work, gives me Undefined redirect_to and nil object #comments errors.
Could you advise me
1. A proper way to do this
2. Syntax
3. Any thing to do to config.rb ?
you want to create a partial that you use to render the comments in the comments index view, and also in your view for the aboutus page
# in about_us and in 'comments#index'
<%= render :partial 'path/to/_partial' %>
#in the about_us controller, or whatever controller dispatches the about us view
#comments = Comment.all.where(:my_conditions)
#partial view
<% #comments.each do |comment| %>
..
<% end %>

Resources