RoR: How to define a method for a partial? - ruby-on-rails

I am trying to render a partial on a page...like so
../devise/sessions/new.html.erb
<%= render partial: '/tweets/latest_tweets' %>
All good
In the partial I would like to do "each do" like so...
../tweets/_latest_tweets.html.erb
<% #tweets.each do |tweet| %>
<%= tweet.content %>
<% end %>
I get undefined method `each' for nil:NilClass
How do I define this method for my partial in my tweets controller?
I have index like so
tweets_controller.rb
def index
#tweets = Tweet.all
end
Which is fine for the index but I don't know how to do same for my partial (I tried just defining my partial like the index but that did not seem to work)
Anyone have a solution I could try?
ty

You need to pass the collection when rendering the partial. It'll give something like this:
devise/sessions/new.html.erb
<%= render partial: 'tweets/latest_tweets', collection: #tweets, as: :tweet %>
tweets/_latest_tweets.html.erb
<%= tweet.content %>
Just like that, and it will iterate through your collection automatically.
Fore more info, please read Rails - Layout and Rendering

Related

Rails 6: Render a partial if only I'm using a method from my controller

I have a Users controller, with index, show, edit and destroy methods. In my layouts/ folder, I have a general-purpose user.html.erb layout that renders some partials. These partials are of course producing errors due some of the info isn't available, like #user.name, for example. I've tried to render that partial always when I'm in a def show state, something like:
<% if Users.show %>
<% render "shared/asides/users" %>
<% else %>
Other partials
<% end %>
I've tried several ways and I always get errors. I feel totally lost even trying to find out this on the Rails documentation nothing seems to be indicated there too.
Your problem is, as you say, you're trying to display things associated with a user, like #user.name, but there is no #user.
So why not check for #user before showing the partial? Or if you have a collection of users, I'm guessing #users?
<% if #users %>
<%= render "shared/asides/users" %>
<% else %>
<%= Do something else %>
<% end %>
Of maybe a bit neater:
<%= render (#users ? path/to/partial_a.html.erb : path/to/partial_b.html.erb) %>
You can make a special layout for your action. Then, at the end of action add layout to render.
def show
...
render layout: "custom_layout"
end

How Rails render finds variable

Simple example:
index.html.erb:
<% #posts.each do |post| %>
<%= post.title %>
<% end %>
I can refactor this and move content to the _post.html.erb partial:
index.html.erb:
<%= render #posts %>
_post.html.erb:
<%= post.title %>
So how Rails passes attributes of every post without creating a block?
My posts_controller index action has only #posts = Post.all defined.
I thought that maybe by the name of the partial (post), but looks like its another Rails convention (plural and singular naming). Is it?
Many thanks for sharing!
Rails determines the name of the partial to use by looking at the model name in the collection. The full syntax to render a collection is as follows:
<%= render partial: "post", collection: #posts %>
However there is a shorthand for this:
<%= render #posts %>
According to docs:
When a partial is called with a pluralized collection, then the
individual instances of the partial have access to the member of the
collection being rendered via a variable named after the partial. In
this case, the partial is _post, and within the _post partial, you can
refer to post to get the instance that is being rendered.
You may find detailed explanation in rails guides

NoMethodError while rendering a partial

I have a welcome.html.erb page with welcome_controller. On this page I try to render a partial which belongs to Screen model, but it returns NoMethodError: undefined method 'each' for nil:NilClass. Here's the code:
welcome.html.erb:
<%= render 'screens/all` %>
_all.html.erb:
<%= #screens.each do |screen| %>
<%= link_to screen do %>
<img src="">
<% end %>
<% end %>
screens_controller.rb:
def all
#screens = Screen.all.order('created_at ASC')
end
Hey you are doing wrong.
def all
#screens = Screen.all.order('created_at ASC')
end
That method you have in screens_controller.rb
You need to write the instance inside the welcome method at welcome_controller.rb, That way it will not give error to you.
That way you can access the partial and one more thing pass the variable in locals with partial and use that instead of the actual instance.
<%= render :partial =>'screens/all`, :locals => {:screens => #screens} %>
The instance variable you're using (#screens) should be coming from whatever controller action renders welcome.html.erb. You should then pass it explicitly as a local (like Bharat shows in his answer).
you Forgot to pass the variable
Try using
<%= render 'screens/all',:screens => #screens %>

Cannot render partial of another module and pass variables

I am sorry in advance as I know this should be an easy one but I am stuck. I have a show view for "Category" in which I am trying to display related has_many "Subcategories". I am calling the partial by using the following:
<%= render partial: 'subcategories/subcategory', locals: {category: #category }%>
I have an html file in the Subcategories view folder properly named and the partial view loads. I know this because the partial has the code
<%= #category.name %></p>
which shows the correct Category name within the partial. However, when I try to load any of the subcategory data by calling
<% #subcategories.each do |subcategory| %>
<%= subcategory.name%>
<% end %>
I get the error: NoMethodError in Categories#show, undefined method `each' for nil:NilClass
I'm sorry to ask such a basic question but I will be using partials from related modules extensively in this project.
Replace this:
<%= render partial: 'subcategories/subcategory', locals: {category: #category }%>
with this:
<%= render #category.subcategories %>
Then in the partial app/views/subcategories/_subcategory.html.erb do this:
<%= subcategory.name %>

Strange routing in rails render partials

I'm new to rails and thought I had finally figured out some of this routing stuff, but have been going in circles with this bit all day.
I was following a tutorial about building a twitter like service, and I've got the basics working from the tutorial, but with Mongo instead of mySql.
I've got 3 types of pages.
The home page which is showing all the posts ordered by date
The user page which is showing the posts from a specific user
The posts page which is showing posts from a users friends.
So for each page, I've done the following
1) created a method in the corresponding controller to get the correct posts
2) created a _posts.html.erb page with the display parameters, which are slightly different on each page
3) referenced the partial in the index.html.erb page for each view.
The controller entries look like this
def index
#posts = Post.all(:order => 'created_at DESC')
end
or
def posts
#posts = Post.all(:conditions => {'user_id' => params[:id]}, :order => 'created_at DESC')
end
and the partials are
<%= render :partial => #posts %>
In each view is a _posts.html.erb file, and each is slightly different
home/_posts.html.erb looks like this
<%= div_for post do %>
Posted <%= time_ago_in_words(post.created_at) %> ago
Posted By <%= post.user_id %>
<%= post.text %>
<% end %>
while posts/_post.html.erb looks like this
<%= div_for post do %>
Posted By <%= post.user_id %>
<%= post.text %>
<% if post.created_at > 52.hours.since %>
<%= distance_of_time_in_words_to_now(post.created_at) %>
<% else %>
<%= post.created_at.strftime("%c") %>
<% end %>
<% end %>
Now the strange part is that on all the pages index.html.erb, users/show.html.erb, posts/index.html.erb, the partial that is being displayed is the posts/_post.html.erb. The others are being completely ignored.
my understanding was that render :partial would take the #posts and render _posts.html.erb from the current view. But this isn't happening, as only the posts/_post.html.erb is being rendered from all views.
I've looked in the routes.rb file, but don't have anything in there that would cause this problem.
Can anybody tell me why I am not displaying the proper partials?
-----------Edited --------------------------------
The directory structure for views is as follows
views
- home
-_post.html.erb
-index.htlm.erb
- layouts
- posts
-_post.html.erb
-index.html.erb
-posts.html.erb
- sessions
- users
-_post.html.erb
-new.html.erb
-show.html.erb
I hope that helps.
"post", :collection => #posts%>
maybe rails automatically defines path to the partial when you pass only collection
You're passing the collection as the argument that rails is expecting to be the name of the partial. Your call to render should look like this
<%= render partial: "post", collection: #posts %>
This will render app/views/posts/_post.html.erb, passing the local variable post to the partial.
Additionally, (is sometimes handy) there's an iteration object that is made available to this view, partial_name_iteration, that has information about the total size of the #posts collection, and the index of the current object.

Resources