i am facing a precarious condition here. I need to partially render a page that does not have a leading underscore.
<%= render(:partial => "contact" ,:controller=>"home") %>
this will look for
app/views/home/_contact.html.erb
but i want it to look for
app/views/home/contact.html.erb
is there a way of doing this.?
Thanks
<%= render :file => '/homes/contact' %>
You should not try to bypass the conventions if not really necessary. I guess contact.html.erb contains a form. Put this into app/views/home/_contact.html.erb and render it in app/views/home/contact.html.erb.
Or as fl00r answered:
<%= render :file => '/homes/contact' %>
As eteubert points out, one of the strengths of Rails is its opinionated nature. What you are trying to do here is bend that to your will. Don't. If you need to render something in another page as a partial, then you really should follow convention and extract a partial from the original page. If there's a form in that page for example, extract it out into a partial and have the original page render the partial as well.
You'll find the less you try to fight Rails, the easier things become.
Related
In rails, I often run into the situation where inside the views I'll do something like
<% if #some_condition_previusly_established_in_a_controller %>
<div class="one">123</div>
<% else %>
<div class="two">something else</div>
<% end %>
It looks a bit cluttery. Is this an acceptable way of working with views or not?
Unless you can think of a way to re-write this as a helper method, you're basically stuck with it looking kind of ugly. That's just how ERB is, as it was intended to be a minimal way of injecting Ruby into an otherwise plain-text template, not as something necessarily streamlined or elegant.
The good news is a syntax-highlighting editor will usually make your <% ... %> ERB blocks look visually different from your HTML so that can dramatically improve readability.
It's also why other representations like HAML have been created where that syntax is a lot less cluttered:
- if some_condition_previusly_established_in_a_controller
.one 123
- else
.two something else
For one or two such conditional logic in your views, I guess its fine but when your code gets bigger and you have multiple if..else..end and looks "cluttery", I think you should look at implementing "Presenter Pattern" which greatly cleans up your views by separating your logic to Presenters.
Here is a great tutorial I followed from Ryan Bates in his Rails Casts series on "Presenter Patterns from scratch". http://railscasts.com/episodes/287-presenters-from-scratch.
Have you tried?
<% #some_condition_previusly_established_in_a_controller ? <div class="one">123</div> : <div class="two">something else</div> %>
If your view contains lots of tags and HTML elements, you can put them into partials and logic into model
View:
<%= render :partial => #model.status %>
<%= render :partial => "file/path/#{#model.status}" %> # if your partial is in some different folder
If your status is one, then it would render the file _one.html.erb
If it is two, then it would render the file _two.html.erb automatically.
Model:
def status
if #some_condition
"one"
else
"two"
end
end
Yes, that is the standard (and yes, it looks cluttery).
If you're looking for a possibly cleaner alternative, check out: Conditional tag wrapping in Rails / ERB
You can always move the logic to the controller and leave the view clean(er).
Controller:
if #some_condition
#div_class = :one
#div_content = 123
else
#div_class = :two
#div_content = 'something else'
end
View:
<div class="<%= #div_class %>"><%= #div_content %></div>
Or using a helper:
<%= content_tag :div, #div_content, class: #div_class %>
I've had a problem with the following issue in Rails and ASP.Net MVC. Often there are multiple widgets of functionality on a page, yet one controller action is supposed to render the page. Let me illustrate:
Let's say I have a normal e-commerce site, and the menu is made of categories, while the page is to display an group of products.
For the products, let's say I have an action on a controller that looks something like:
def product_list
#products = Products.find_by_category(:name => 'lawnmowers')
end
And I have a layout with something like
<div id="menu"><%= render :partial => 'menu' %></div>
<div id="content"><%= yield %></div>
The products have a view...
<%= render :partial => 'product', :collection => #products %>
(note I've ommited the product view as irrelevant)
And the menu has a partial...
<% Category.each {|c| %>
<%= render :partial => 'menu_node', :locals => { :category => c } %>
<% } %>
The line I have a problem with is the "Category.each.do" in the view. I'm fetching data in the view, as opposed to using variables that were set and bound in the controller. And it could easily be a more complex method call that produces the menu.
The solutions I've considered are:
-A view model base class that knows how to get various pieces of data. But you could end up with one of these for each conceptual "section" of the site.
-a local variable that populates at the top of each method (violates DRY)
-the same thing, but in a before_filter call
None of these seem very elegant to me. I can't help but look at this problem and think that a MVP presenter per view (not screen) is a more elegant solution.
ASP.Net MVC has render action (different from rails render :action), which does address this, but I'm not sure what I think of that solution.
Thoughts? Solution suggestions?
Added Note:
The answers provided so far are good suggestions. And they apply to the example I gave, where a menu is likely present in every layout, and is clearly secondary to the product data.
However, what if there is clearly no second class citizen? Portal type sites commonly have multiple unrelated widgets, in which each is important.
For example, What if this page was displaying weather trends, with widgets for temperature, humidity, and precipitation (and each is a different model and view type).
In rails we like to have a concept of thin-controllers, thick-models. So I think you're right to not want to have variables set in the controller.
Also, in order to enable a more-complex method later on, I recommend doing something like:
/app/controllers/application_controller.rb
before_filter :add_menu_nodes
def add_menu_nodes
#menu_nodes = Category.menu_nodes(current_user)
end
/app/views/layouts/application.html.erb
<%= render :partial=>:menu, :locals=>{:categories=>#menu_nodes} %>
/app/models/category.rb
def self.menu_nodes(current_user)
Category.all.order(:name)
end
That way in the future you could update Category.menu_nodes with a more complicated solution, based on the current user, if you need.
Forgive me if I butcher the Ruby (or misunderstand your question), but what's wrong with
class section_helper
def menu( section )
// ...
menuBuiltAbove
end
end
in the view
<%= section_helper.menu( 'section' ) %>
?
Ryan Bates' nifty_scaffolding, for example, does this
edit.html.erb
<%= render :partial => 'form' %>
new.html.erb
<%= render :partial => 'form' %>
_form.html.erb
<%= form_for #some_object_defined_in_action %>
That hidden state makes me feel uncomfortable, so I usually like to do this
edit.html.erb
<%= render :partial => 'form', :locals => { :object => #my_object } %>
_form.html.erb
<%= form_for object %>
So which is better: a) having partials access instance variables or b) passing a partial all the variables it needs?
I've been opting for b) as of late, but I did run into a little pickle:
some_action.html.erb
<% #dad.sons.each do |a_son| %>
<%= render :partial => 'partial', :locals => { :son => a_son } %>
<% end %>
_partial.html.erb
The son's name is <%= son.name %>
The dad's name is <%= son.dad.name %>
son.dad makes a database call to fetch the dad! So I would either have to access #dad, which would be going back to a) having partials access instance variables or I would have to pass #dad in locals, changing render :partial to
<%= render :partial => 'partial', :locals => { :dad => #dad, :son => a_son } %>, and for some reason passing a bunch of vars to my partial makes me feel uncomfortable. Maybe others feel this way as well.
Hopefully that made some sense. Looking for some insight into this whole thing... Thanks!
In recent versions of Rails it is quite a bit easier to render partials and pass locals to them. Instead of this.
<%= render :partial => 'form', :locals => { :item => #item } %>
You can do this.
<%= render 'form', :item => #item %>
I don't do this in the Nifty Scaffold generator to keep backwards compatibility, but I'll change this in a future release.
As for whether it's acceptable to use instance variables in partials. I think it is. In all practicality, what is the downside? Certainly things can get out of hand if you aren't consistent, but I like to apply these guidelines.
Never create an instance variable just to share it between partials. Usually this means you will only be sharing the controller resource object.
If the partial is the same name as the resource, pass it as a local with <%= render #item %>.
If the partial will be shared across multiple controllers then only use locals.
This is what works well for me anyway.
Bonus tip: if you find yourself passing in a lot of locals into a partial and you want some of them to be optional, create a helper method which renders the partial. Then always go through the helper method so you can make a clean interface with optional args for rendering the partial.
Using #instance_variables in partials is bad design.
Using instance variable in partials works, but it can make it harder to maintain applications if changes are ever needed.
The downside of using instance variables in partials is that you create a dependency in the partial to something outside the partial's scope (coupling). This makes the partial harder to reuse, and can force changes in several parts of the application when you want to make a change in one part.
Partials that use instance variables:
must change when the instance variable in any controller that uses the partial changes either the instance variable name or its type or data structure
cause all controller actions that use the partial to change in the same way at the same time when there are changes to how the instance variable is used
discourage reuse, as they can only easily be reused in actions that set up instance variables with the same name and data
Instead, pass locals to the partials:
<%= render 'reusable_partial', :item => #item %>
Now, because the partial only references item and not #item, the action that renders the view that renders the reusable_partial is free to change without affecting the reusable_partial and the other actions/views that render it:
<%= render 'reusable_partial', :item => #other_object.item %>
Also, this can be reused in contexts where there is no #item:
<%= render 'reusable_partial', :item => #duck %>
If my #duck changes in the future and no longer quacks like reusable_partial expects it to (the object's interface changes), I can also use an adapter to pass in the kind of item that reusable_partial expects:
<%= render 'reusable_partial', :item => itemlike_duck(#duck) %>
Always?
There are plenty of situations where you probably don't need de-coupled partials like this, and it's easier in the short run to use an instance variable. However, it's hard to predict the future needs of your application.
As such, this makes for good general practice while having relatively low cost.
You can have it both ways. At the top of your partial:
<% item ||= #item %>
That way, it works with or without passing the local variable, providing a sane default, but not inhibiting alternate usage of the partial.
I vote for a) for a very specific reason -- DRY! If you start passing a variable like that, the next thing you know it's a mess. Let's say you need to change the way your variable is named or something else about it. You'll need to go to ALL your views and change them instead of ONE partial.
Also, if you change your partial it will change on all your views, so you'll need to know which views are used. A proper IDE should be able to help you with that, but I also like having a small comment section at the top of the view where I just mention where it's used and why. This helps another programmer and it helps you to remember in case you need to come back to a partial and modify. But the whole point of the partial is to call it WITHOUT having to pass anything from the view, so that you don't have to modify all places where partial is called from if that variable changes somehow.
Ultimately this is a design choice, and to be honest unless you are running a facebook the extra lookup you do is not that big of a deal, but it's just not very DRY.
P.S.: Just thought about it. You can actually abstract the way you call partial in a helper method, so then if the way you call your partial needs to change, you just need to modify one place.
Warning: Noob here.
I know this is a trivial subject but I'm having a lot of difficulty in figuring out how exactly I can simplify my views by moving parts of them into helpers. For example, I've always read that conditionals in your views are prime candidates for extraction into helpers, but I couldn't really find examples of this, and my attempts to achieve this failed.
For example, suppose I have:
#index.html.erb
<% for beast in #beasts do -%>
<% if beast.dead? -%>
<%= beast.body %>
<%= link_to "bury", bury_beast_path( :id => beast.id ) %>
<% else -%>
<%= beast.body %>
<%= link_to "kill!", kill_beast_path( :id => beast.id ) %>
<% end -%>
<% end -%>
It annoys me a little to have this in my view, but how exactly could I move this to a helper instead? And further simplify it, if possible. (I've read somewhere that conditionals are bad but it's just beyond me how you could program anything without them.)
Another example: I need to id my body tags with the format controller_action. The best I've got so far is this:
#index.html.erb
<body id="<%= controller_action %>">
…and…
#application_helper.rb
def controller_action
#id = #controller.controller_name + "_" + #controller.action_name
end
I'm no expert, but that's still ugly even to me.
To make things more complicated, Ryan Singer said something I liked: to treat ERB like an image tag, using helpers to "reveal intention". Then in the next breath saying that you should have no HTML in helpers for that is the way to hell. WTF? How are both things compatible? If it's come to the point where you can just declare behaviors in the view, surely there should be a lot of HTML to be rendered behind the scenes? I can't grasp it.
So, that's basically it. I'd appreciate if anyone could share some thoughts on this, or point me to some good in depth reading on the subject – which I've found to have a really weak coverage on the web. I've already googled it to exhaustion but who knows.
Refactoring makes your views easier to maintain. The problem is choosing where the refactored code goes.
Your two choices are partials and helpers. There's no stone-set rules dictating which should be used where. There are a couple of guidelines floating around like the one stating that helpers should not contain HTML.
Generally partials are better suited for refactoring sections that are more HTML/ERB/HAML than ruby. Helpers on the other hand are used for chunks of ruby code with minimal HTML or generating simple HTML from parameters.
However, I don't agree with the sentiment that helpers should contain no HTML at all. A little is ok, just don't over do it. The way helpers are processed hinder their use for producing large amounts of HTML. Which is why it's suggested that your helpers contain minimal amounts of HTML. If you look at the source the helpers that ship with rails you will notice that most of them generate html. The few that don't, are mainly used to generate parameters and evaluate common conditions.
For example, any of the form helpers or link_to variants fit the first form of helpers. While things like url_for and logged_in? as supplied by various authentication models are of the second kind.
This is the decision chain I use to determine whether to factor code from a view into a partial or helper.
Repeating or nearly identical statements producing a single shallow html tag? => helper.
Common expression used as an argument for another helper? => helper.
Long expression (more than 4 terms) used as an argument for another helper? => helper.
4 or more lines of ruby (that is not evaluated into HTML)? => helper.
Pretty much everything else => partial.
I'm going to use the code you're looking to refactor as an example:
I would refactor the view in the question this way:
app/helpers/beast_helper.rb:
def beast_action(beast)
if beast.dead?
link_to "bury", bury_beast_path(beast)
else
link_to "kill!", kill_beast_path(beast)
end
end
app/views/beasts/_beast.html.erb:
<%= beast.body %>
<%= beast_action(beast) %>
app/views/beasts/index.html.erb:
<%= render :partial => "beast", :collection => #beasts %>
It's technically more complicated, because it's 3 files, and 10 lines total as opposed to 1 file and 10 lines. The views are now only 3 lines combined spread over 2 files. The end result is your code is much more DRY. Allowing you to reuse parts or all of it in other controllers/actions/views with minimal added complexity.
As for your body tag id. You should really be using content_for/yield. For that kind of thing.
app/views/layouts/application.html.erb
...
<body id="<%= yield(:body_id) %>">
...
app/views/beasts/index.html.erb
<% content_for :body_id, controller_action %>
...
This will allow you to override the id of the body in any view that requires it. Eg:
app/views/users/preferences.html.erb
<% content_for :body_id, "my_preferences" %>
The first thing I'd do would be this:
#index.html.erb
<%= render #beasts %>
#_beast.html.erb
<%= beast.body %>
<%= link_to_next_beast_action(beast) %>
#beast_helper.rb
def link_to_next_beast_action(beast)
if beast.dead?
link_to "bury", bury_beast_path( :id => beast.id )
else
link_to "kill!", kill_beast_path( :id => beast.id )
end
end
What I've done is separate out the rendering of the beast into a partial which uses collection semantics.
Then I've moved the logic for showing the kill/bury links into a beast helper. This way if you decide to add another action (for example, 'bring back from dead'), you'll only have to change your helper.
Does this help?
A third choice is to use a view model from the Cells gem. This is a very popular framework that brings object-orientation to the view layer in Rails.
# app/cells/beast/cell.rb
class Beast::Cell < Cell::Concept
def show
return dead if model.dead?
kill
end
private
def dead
link_to "bury", bury_beast_path( :id => model.id )
# you could render a view here, too!
end
def kill
link_to "kill!", kill_beast_path( :id => model.id )
end
end
You then render a view model using a helper (in the view or controller).
# app/views/beasts/index.erb
<%= concept(:beast, #beast).call %>
<%-# this returns the link content %>
That's all! You can test this cell isolated in a separate test. Cells also give you view rendering, view inheritance and many more things.
As an example, you could use a view for the kill link.
# app/cells/beast/cell.rb
class Beast::Cell < Cell::Concept
# ..
def kill
render :kill
end
end
This renders the cell's killer view.
# app/cells/beast/views/index.erb
<%= link_to "kill!", kill_beast_path( :id => model.id ) %>
Note the location of the view, it's nicely packaged into the cell directory.
And, yes, cells can do HAML and any other template engine supported by AbstractController.
Another startegy would be to not use templates and helpers at all.
For rendering you could :
render your views directly from your controllers using render(:inline => ). If you still want to keep Views and Controllers formally separated you can create modules / mixins that you include into the controllers.
or create your own view classes and use them to render your response.
The idea behind this is that helpers and rails erb templating system don't take advantage of OOP, so that at the end of the day you can't define general behaviours that you'll specialize according to each controller's/request's needs; more often than not one ends up rewriting very similar looking chunks of code, which is not very nice from a maintenance standpoint.
Then if you still need some helper methods (eg. form_tag, h, raw, ...) you only have to include them in your controller / dedicated view class.
See this : rails-misapprehensions-helpers-are-shit for a fun but useful article.
EDIT: to not sound like a complete douche, I'd say implementing this depends on how big your application is supposed to be, and how often you're going to have to update your code. Plus, if you're delegating the design to a non-programmer, he/she may well be in for some programming courses before digging into your code, which admittedly would be less directly understandable than with templates syntax.
I'm rendering a partial in a collection like this :
<%= render :partial => 'issues/issue', :collection => #issues %>
Inside the partial, I want to render a element unless it's the last in the collection. I could of course, render the partial like this
<%= render :partial => 'issues/issue', :collection => #issues, :locals => {:issue_count => #issues.length } %>
then put this inside my partial
<% unless issue_counter + 1 == issue_count %>
<hr />
<% end %>
but I don't want to have to explicitly set the local in the render call, and I the collection isn't always going to be called #issues, so I can't just access the instance varibale. Is there some way to access the length of the collection automatically inside the partial to tell where in the collection the object falls? If there's not already, is it possible to add this in such a way that I'll automatically get the issue_count local? Any help on this will be much appreciated.
Thx,
-C
You can supply the :spacer_template option to your render :partial => X, :collection => Y call. See the ActionController::Base documenation for usage.
It probably feels heavy-handed to specify an entire partial file for a simple <hr /> element, but going this route keeps your intention clear and keeps the item partial free of unrelated divider markup.
I think you can make this happen if you modify the render_partial_collection method.
As a side note: Seems to me like you should instead use CSS on a unordered list: I get the feeling you are inserting markup HRs to style instead of using it to semantically separate items in the collection (in mark-up semantics).