Rails 5 rendering partials and passing data - ruby

I'm having trouble getting traction on what the general ways data gets passed around from and is made available to partials.
For example:
I have a controller handing off an instance variable to a template that renders a partial:
static_pages_controller.rb:
def home
#feed_items = current_user.feed
end
home.html.erb:
<%= render 'shared/feed' %>
_feed.html.erb:
<%= render #feed_items %>
Now, inside my User model is an instance method that reaching into the database to get her posts:
user.rb:
def feed
Micropost.where("user_id = ?", id)
end
So somehow because Micropost.where(...) returns a collection of microposts is that how Rails knows to go from _feed.html.erb to another partial where the <li> is defined for how microposts want to be defined?
_micropost.html.erb:
<li id="micropost-<%= micropost.id %>">
<%= link_to adorable_avatar_for(micropost.user, size: 50), micropost.user %>
</li>
And also is it just a convention that because I'm really handling a collection of microposts that Rails knows to give the micropost variable?

Your questions are answered in the Ruby on Rails Guides on Layouts and Rendering. It's worth reading the information on partials that comes before the quoted passages below as well:
Every partial also has a local variable with the same name as the
partial (minus the underscore). You can pass an object in to this
local variable via the :object option:
<%= render partial: "customer", object: #new_customer %>
Within the customer partial, the customer variable will refer to
#new_customer from the parent view. (Earlier the Guide instructs that to specify other options for render(), e.g. object:, you have to explicitly specify partial: and the name of the partial.)
If you have an instance of a model to render into a partial, you can
use a shorthand syntax:
<%= render #customer %>
Assuming that the #customer instance variable contains an instance of
the Customer model, this will use _customer.html.erb to render it and
will pass the local variable customer into the partial which will
refer to the #customer instance variable in the parent view.
3.4.5 Rendering Collections
Partials are very useful in rendering collections. When you pass a
collection to a partial via the :collection option, the partial will
be inserted once for each member in the collection:
index.html.erb:
<h1>Products</h1>
<%= render partial: "product", collection: #products %>
_product.html.erb:
<p>Product Name: <%= product.name %></p>
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 _product, and within the _product partial,
you can refer to product to get the instance that is being rendered.
There is also a shorthand for this. Assuming #products is a collection
of product instances, you can simply write this in the index.html.erb
to produce the same result:
<h1>Products</h1>
<%= render #products %>
Rails determines the name of the partial to use by looking at the
model name in the collection. In fact, you can even create a
heterogeneous collection and render it this way, and Rails will choose
the proper partial for each member of the collection:
index.html.erb:
<h1>Contacts</h1>
<%= render [customer1, employee1, customer2, employee2] %>
customers/_customer.html.erb:
<p>Customer: <%= customer.name %></p>
employees/_employee.html.erb:
<p>Employee: <%= employee.name %></p>
In this case, Rails will use the customer or employee partials as
appropriate for each member of the collection.
In the event that the collection is empty, render will return nil, so
it should be fairly simple to provide alternative content.
<h1>Products</h1>
<%= render(#products) || "There are no products available." %>

Related

Ruby render another controller partial

I have a controller and in the index view i am trying to render a partial from another controller. Here is the other controller:
class ModelController < ApplicationController
def view
#model = Model.where('equipment_id' => params[:equipment_id])
render :partial => 'view_model'
end
end
And in the index view I am trying this:
<div id ="mdl-inner_box" class="inner_box">
<%= render "model/view", :#model => Model.first %>
</div>
And my partial view is this:
<% #model.each do |m| %>
<div> <%= m.name %> </div>
<% end %>
I am getting this error:
ActionView::MissingTemplate at /equipment
Missing partial model/view with {:locale=>[:en], :formats=>[:html], :handlers=>[:erb, :b
What is the correct way to do this?
Thanks
There are too many errors to really address this question!
First of all if you are showing code for your index action, why is it the view action?
I have a controller and in the index view...
class ModelController < ApplicationController
def view
# should be
def index
In your index view, presumably app/views/models/index.html.erb you render a partial, which points to app/views/model/_view.html.erb. That should probably be models
<%= render "model/view", :#model => Model.first %>
<!-- should be -->
<%= render "models/view", :model => #model %>
And set #model in your controller. You can put Model.first into the view itself, but I think that breaks MVC pattern a little bit.
Finally in the partial, you access the class variable #model defeating the purpose of passing it as a local. You also call .each on it, which is a method for looping through collections, not for individual records. For example you would do #models.each and never #model.each.
<% #model.each do |m| %>
<div><%= m.name %></div>
<% end %>
<!-- should be something like -->
<%= model.name %>
Long story short, seems to me you're pretty lost, so I would start with a good book about Ruby on Rails before you continue. Here's a free one: http://ruby.railstutorial.org/ruby-on-rails-tutorial-book?version=4.0

rails sending code block to partial

Rails 3.2.13 & ERB
I am trying to get send some link_to items to a partial. I am sending in a title to the partial successfully as below.
<%= render :partial =>'form',
:locals => {:page_title => t(:'<h2>Editing Feature</h2>')}
What I dont like is that I am currently doing this:
<%= link_to 'Show', #feature %> |
<%= link_to 'Back', features_path %>
as part of the primary page. I would like to take this codeblock and send it to the partial for rendering there. The primary reason is the simple_form is defined in the partial and I have a well that contains everything on that page. Except for the two link_to items down on the bottom of the page. If I could pass them into the partial somehow (I assume as a code block) then I can decide where to place them and how to render them in the form itself instead of kind of as an afterthought.
Thanks.
Typically we use partials to break off HTML chunks into separate modular components and reduce repetition. Partials have the same variable context as the template that rendered them, so as-is, you wouldn't have any trouble simply relocating your links to your partial and everything should just work.
I think the better practice, however, would be to pass your instance variable as a local to reduce coupling with your controller. Something like:
Your view:
<%= render :partial =>'form',
:locals => {:page_title => t(:'<h2>Editing Feature</h2>'),
:feature => #feature} %>
_form.html.erb:
<%= link_to 'Show', feature %> |
<%= link_to 'Back', features_path %>
This way, if you were to render the partial elsewhere in your application you don't need to have an instance variable handy. An example situation where this could be useful would be looping through multiple "features" (a la an index view) and spitting out the relevant HTML as defined in the partial.

2 instance variables of the same name in different controllers

I finished Michael Hartl's Ruby on Rails Tutorial. Now I'm working on the suggested exercises. The application he builds is basically a Twitter clone where one can post Microposts and they appear in your feed http://ruby.railstutorial.org/chapters/user-microposts#fig-micropost_created
The main page is in home.html.erb from the StaticPagesController and features a Micropost textbox where one can post Microposts. The code for the textbox looks like so:
<%= form_for(#micropost) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.text_area :content, placeholder: "Compose new micropost..." %>
</div>
<%= f.submit "Post", class: "btn btn-large btn-primary" %>
<% end %>
The #micropost variable is initialized in the StaticPagesController like so:
class StaticPagesController < ApplicationController
def home
if signed_in?
#micropost = current_user.microposts.build
end
end
Now inside the MicropostsController there's a create action like so:
def create
#micropost = current_user.microposts.build(params[:micropost])
if #micropost.save
flash[:success] = "Micropost created!"
redirect_to root_url
else
#feed_items = []
render 'static_pages/home'
end
end
My question is what is the purpose of the first #micropost variable as opposed to the second?
thanks,
mike
The first #micropost becomes available to the view rendered by the first controller method; the second #micropost becomes available to the view rendered by the second controller method. And it just so happens that the two methods are rendering the same view.
The only wrinkle is that since the second controller is conditional. If the create succeeds (passes validation and saves) then there's a redirect, so there's no proper view (although there will be in a moment, after the client-side redirect). But if it fails, then the view gets an object that contains the user-entered values as well as the validation errors which the view can then show to the user.

instance vs local variables in a partial

I'm currently going through Michael Hartl's tutorial Ruby on Rails Tutorial http://ruby.railstutorial.org/ruby-on-rails-tutorial-book. I'm confused about where certain partial variables come from. In his tutorial he creates Users and Microposts. A User can create a Micropost on his main page (called a Feed) and have them posted there. The layout looks like this http://ruby.railstutorial.org/chapters/user-microposts#fig:proto_feed_mockup. Now the User model looks like this (I'm not posting the entire thing):
class User < ActiveRecord::Base
has_many :microposts, dependent: :destroy
def feed
Micropost.where("user_id = ?", id)
end
end
The Micropost model looks like this:
class Micropost < ActiveRecord::Base
belongs_to :user
end
In the text the author says that the feed method inside the User model can be written equivalently like this:
def feed
microposts
end
Why are they the same?
My next questions have to do with partials. On the user's show page (show.html.erb) the _microposts.html.erb is called with this if I'm not mistaken:
<%= render #microposts %>
_microposts.html.erb looks like this:
<li>
<span class="content"><%= micropost.content %></span>
<span class="timestamp">
Posted <%= time_ago_in_words(micropost.created_at) %> ago.
</span>
<% if current_user?(micropost.user) %>
<%= link_to "delete", micropost, method: :delete,
data: { confirm: "You sure?" },
title: micropost.content %>
<% end %>
</li>
My question here is where is the micropost variable come from? Is it the same as the #micropost variable which calls this partial?
Now on the users home page (home.html.erb) there is a call to the _feed.html.erb partial like this:
<%= render 'shared/feed' %>
_feed.html.erb looks like this:
<% if #feed_items.any? %>
<ol class="microposts">
<%= render partial: 'shared/feed_item', collection: #feed_items %>
</ol>
<%= will_paginate #feed_items %>
<% end %>
I know where #feed_items comes from. It's set in a controller. Now _feed_item.html.erb looks like this:
<li id="<%= feed_item.id %>">
<%= link_to gravatar_for(feed_item.user), feed_item.user %>
<span class="user">
<%= link_to feed_item.user.name, feed_item.user %>
</span>
<span class="content"><%= feed_item.content %></span>
<span class="timestamp">
Posted <%= time_ago_in_words(feed_item.created_at) %> ago.
</span>
<% if current_user?(feed_item.user) %>
<%= link_to "delete", feed_item, method: :delete,
data: { confirm: "You sure?" },
title: feed_item.content %>
<% end %>
</li>
So a similar question is where does the variable feed_item come from and what does it contain?
thanks,
mike
Ok, let's see. This is a lot of questions in one go, but...
Why is 'feed' equivalent to 'microposts'?
This is Rails' associations at work. When you use has_many to describe an association, Rails creates a whole bunch of methods based on the association name. In this case, you say that User has_many :microposts, which, among others, creates a User#microposts method.
The instance variable used in the render call (#microposts) is presumably set in a controller action. When you call render in this fashion (with an array of ActiveRecord objects), Rails looks for a partial with a name matching the class name of those objects. In this case, they're MicroPost objects, so it looks for a partial named _micropost and renders it once for each object in the array. When rendering a partial, the object that the partial is associated with can be referred to using a local variable with the same name as the partial. Since this is the _micropost partial, the local micropost variable refers to the object it's rendering.
Once again, the local variable with the same name as the partial refers to the object the partial is rendering. #feed_items is a collection, and for each object in it, you get one rendering of the _feed_item partial, in which the feed_item local variable refers to that object.
Because a user's microposts are associated using has_many, and internally, the relationship is based on the user's id. Getting them "by hand" does essentially the same thing, but with more work.
micropost comes from convention–Rails creates it for you. I don't know what you mean by "the #micropost variable which calls this partial".
Same answer, although it's based explicitly on the template name (IIRC) rather than a singularized name. It contains a single one of whatever #feed_items contains.

Rails forms -- accessing a variable that is not part of the form

I want to make a form for submitting the info needed to create an instance of model X and save it to the database, but I have a slight problem: I know how to add form fields like text areas and what not and then how to make those values accessible when the create method is called, but what if I want to also send make a value that is not part of the form accessible? For example, what if I want to be able to access some text in a <div> of my html document and send that to the create method for model X (so it can be stored in like a content variable or something)? How do I do that?
Short answer is you can't - to send data to the server, it has to be in an form field.
Longer answer - there are ways around this and you have several options - put the text in a textarea and style it to look like an div, or put it in a hidden field when the template is created, or use javascript to copy it into a hidden field ... all depends on what you are trying to do really. Perhaps you could give some more detail?
In your model you want to use attr_accessor
What you can do is use attr_accessor which creates a virtual attribute that you can use in the model but is discarded after that.
For example:
app/models.post.rb
class Post < ActiveRecord::Base
attr_accessor :some_variable
#now you can access 'some_variable' this variable in the model
#try Post.some_variable in the console
end
app/views/posts/_form.html.erb
<div id="form">
<div class="field">
<%= f.label :some_variable %>
<%= f.text_field :some_variable %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
</div>

Resources