Somewhat new to rails, longtime programmer. I've got a question about views, controllers and partials really - wondering if I have this setup well.
I've got a pages controller, and on the index page (really the pages index method) I've got a partial in layouts called featured (ie app/views/layouts/_featured.html.erb) -- I've also got a Featured class. I would like basically the index of the featured class to be drawn here. But of course it's not working. SO the question is:
In the page itself I've got the <%= render 'features/index' %> which I'm beginning to think is the wrong way to go..
Do I axe this partial method and just call <%= render 'features/index' %> and let everything progress natively or
What would be the proper way of routing the featured collection to the partial? Since the controller is actually Pages it seems like I'm fighting against the tide.
<%= render 'features/index' %>
Doing this is wrong given your description. This will try to render a partial from app/views/features/_index.html.erb which you haven't mentioned.
To render the partial at app/views/layouts/_featured.html.erb you would do (perhaps a bit more verbose that is necessary)
<%= render partial: "layouts/featured" %>
The best suggestion I can offer is to pass a collection to this partial
<%= render partial: "layouts/featured", locals: { features: #features } %>
Since it seems your intention is for this partial to appear as a piece of a layout I will assume you wish for this partial to appear on multiple pages. This means on multiple actions you will need to have assigned the set of Feature instances this #features instance variable. One way to do this is a before_action.
before_action :setup_features
# ...
private
def setup_features
#features = Feature.all
end
A good place to start learning more about filters is in the Rails Guide
The partial at "app/view/layouts/_featured.html.erb" can only be rendered with
render 'featured'
and not 'featured/index'
render 'featured/index' will render "app/views/layouts/featured/_index.html.erb
Since the pages controller is really rendering the main index page in it's def index, all I had to do was #features = Feature.all and the variable is available for the partial pulled into the index page.
I need to get used to how simple rails is coming from other languages / frameworks.
Related
Within views/layouts/application.html I have the line <%= yield %>. This line is ultimately replaced by views directly corresponding to controller actions without any problems.
In one of my controllers, I am trying to render a partial instead of the default behaviour:
def show
#service_groups = ServiceGroup.where(deleted_at: nil)
render partial: 'table', locals: {rows: #service_groups, headers: service_group_headers}
end
I'm using a partial in this way so that I can use the same basic table structure for various different database tables (across different controllers).
This render partial code doesn't seem to work with the <%= yield %> line in the application layout. The partial code is just rendered on its own without the surrounding layout.
Why is this?
How do I rectify the problem?
Please let me know if I should be handling this a different way.
Thanks.
(migrating from comments)
What if you created a show.html.erb for that controller and placed render :partial there? It should work.
Explanation: Partials are to be used from "big" views. So, they are not wrapped in the layout on purpose!
Here is my problem with Rails.
Sometimes there is independent blocks at the page (e.g. "Latest news") which has no logical relation to current controller or action. In regular rails MVC stack I would write #news = News.latest in my controller and render 'shared/latest_news', news: #news in my view.
However its too much for me for several reasons. Instead I want to write render 'shared/latest_news', locals_call: "NewsController#latest" in view and that's it.
What should happen behind this row is calling "NewsController#latest" method to receive a hash of locals used in rendering this template.
Does anyone know gem for such calls?
You could make a universal helper method in ApplicationHelper:
def latest_news_tag
render partial: 'shared/latest_news', locals: { news: News.latest }
end
You can call this method in any view you want, e.g. <%= latest_news_tag %>.
I have code like render #posts to render my posts collection in an index template which the PostsController renders.
Now I have an Admin::PostsController that also should render the collection but when my posts controller renders #posts it looks for the admin/posts/_post.html.erb partial. Do I now have to write the partial path explicity? Is this feature by design or a bug? It doesn't seem to make sense.
Yes, you need to supply the path explicitly. And yes, this is by design.
It actually makes sense because Rails is a MVC framework and if you create a controller under a different namespace one would expect separate views for that controller too. Think about convenience, if you wanted to quickly bootstrap an application with a few simple commands, an application where there's a public view of posts and an admin view where all of the admin goodies for editing are, you would EXPECT to have a different directory to store all that admin views.
render #posts is a shortcut for a longer method signature.
In case of PostsController, it is a short cut for render :partial => "post", :collection => #posts; the partial is _post.html.erb and it is expected to be in app/views/posts folder.
In case of Admin::PostsController, it is a short cut for render :partial => "admin#post/post", :collection => #posts; the partial is _post.html.erb, and it is expected to be in app/views/admin/posts folder.
If you want a different partial to be used, you should specify it explicitly.
See the Rendering Collections section of Rails Guides page on Layouts & Rendering for detailed explanation.
I'm very new to RoR, moving from PHP. I have what I hope is a simple question.
Say I have a Model called Article, stored in the table articles.
If I want to display a list of articles on several pages in my site, I might have some simple markup such as;
<% Article.find_each do |article| %>
<div class="article_list_wrapper">
<h1><%= article.title %></h1>
<p><%= article.body %></p>
</div>
<% end %>
Where would I put this markup? I mean in what file; if I put it in a view, then I will have to copy it if I want a similar list in a different part of the site.
Putting it in the Model itself seems intuitive to me, the Article object should know how to render itself, right? But that seems totally against the CMV idea.
And what if I wanted to have several ways of rendering the same object? Like a list view, a full page view etc.
Many thanks, just trying to get into the correct habits from the start.
You would put that portion of HTML markup into what is known as a partial -- something that can be rendered as a small piece of a larger layout. You're right, you wouldn't want to store the format in the model, because you might wish to render that specific HTML for web browsers and render very similar XML or JSON for clients using an API and render some other very similar content into ASN.1 or YAML for further other clients. The "view" really should stay associated with the views.
With this specific example, you would probably go one further and provide the articles to render via a variable rather than letting the view find the articles itself:
Controller:
def flubber:
#articles = Article.find_each(some_criteria)
end
View:
<div class="article_list_wrapper">
<%= render :partial => "article_list", :collection => #articles %>
</div>
And then provide a View for the corresponding controller with the name _article_list:
<h1><%= article.title %></h1>
<p><%= article.body %></p>
If the <div class="..."> is going to be identical in every single use of this partial, you could either pass a :template to the partial, or put it into a view helper, or put the entire render with the :template argument in a view helper. (Either the first or last approach here is what I'd do -- the <div class="..."> doesn't seem so important to require its own file, but if it were more complicated, it might -- and then I wouldn't want to give the partial :layout argument every time I needed it.)
MVC (Model-View-Controller):
The Model has (primarily) the database piece and business logic.
The Controller controls application flow.
The View shows the info, e.g. the browser view.
So the markup you show which has a bunch of HTML goes in the view.
That is app/models/views/article.rb
The Controller is the part that gets the info.
You should actually have #article = Article.all in your controller and then just use #article.each instead of Article.find_each in your view.
If you have conditions you can apply them directly on the Controller find but the better approach is to learn about how you can use model finders with scopes and then use those scopes from the controller. Always try and push things up from View to Controller to View and follow the 'fat Model, thin Controller' approach when practical.
For reuse partials can help but as better understanding of rails will help more.
See railscasts by Ryan Bates. Incredible tutorials.
You might also like my own bookmarks for rails at my (rails) linker app.
You can use partials for this.
In my rails application, I render a partial on multiple pages, and in that partial is a variable. So currently, lets say I have 5 pages that render :partial => "partialname", and inside of partialname is #variable.
Can I have it so that partialname has its own action with #variable instantiated inside, rather than having #variable be called 5 times from each action that renders the partial?
Thanks!
I would create a before_filter on all the methods that need the common behavior.
But if you really want the partial to have its own "action," make a helper method that does whatever "action-y" things you want and then renders the partial. That works out to essentially the same thing. I've done this before to make a template-type partial that contains various pieces of data that need processing.
Rails Sub-controllers?
See my answer on this.
Very similar method here, using before filters either using controller inheritance or modules when needed.
So, is this a problem of code running 5 times per request that you'd rather not? Like, you've got a partial and in it is:
#my_var = MyModel.some_expensive_method
If so, you could just cache the result in the model:
def cached_some_expensive_method
#some_expensive_method ||= some_expensive_method()
end
you could load #variable from the view:
<% #variable = Variable.find(:whatever) %>
but some consider this bad practice in not adhering to strict MVC. This does have the benefit of supporting fragment caching out of the box:
<% cache({:variable_id => :whatever}) do %>
<% #variable = Variable.find(:whatever) %>
. . .
<% end %>
Is there a common model that's being rendered in the main views that you could delegate the variable access to?
<%=h #model.variable %>