print line in rails only for a specific page - ruby-on-rails

I am new in rails and have the following issue:
I have a view that renders from the layout across several pages, it is in fact a part of the header. I want to remove a specific line from the header and hide it only for one page. I have tried to add a condition in the view to check if the page rendered comes from a specific controller/action but it doesn't work. what is the best practice for this case?
thanks

Just keep a instance variable in controller action and set is as true. Use this variable to with conditions to include/exclude specific code.
controller action
#include = true
view
if #include.present?
//place the line which should be excluded
end

I've asked a very similar question, and you are allready on a good way:
Use a condition like
<% if current_page?(view_path)==false %>
<your line>foobar</your line>
<%end%>

In the view you can access the controller from params[:controller] so you could have
<% if params[:controller] == foo %>
<p>conditionally shown</p>
<% end %>
Its not always best practise to use params directly inside the view though...

Related

Setting content_for misunderstanding

I'm using this tutorial to set bootstrap modal content in forms, but I want to set the title...
I think I don't understand how to set the title content_for method...I understand it for templating, but if I want to send a title to the modal, is it best to make a helper for that? Is there a better Rails 4 way to do this?
Please advise, and remember, I'm not a CE--I've looked at the rails doc and google searched, so please don't demean my question by posting a google link. Thanks!
If you're going to be rendering the title of the modal dynamically, it's typically better to use a helper method. This will keep your view logic DRY and readable. This method will accept an argument for the title and if none is present it will render a default title.
In application_helper.rb:
def modal_title(title)
if title.empty?
"My Default Title"
else
title
end
end
In your modal partial where the title should appear:
<%= modal_title(yield(:title)) %>
In the view, you will have access to dynamically set the title using content_for. For example, you could pass a string as your title or pass an instance variable from your controller.
<% content_for :title, #your_variable %>

render all passed parameters quickly in rails

I have a form that populates various values, then posts those values to a page when the user submits. Now, I wish to see what params[] contains (by displaying it on the page I post to) just to fool around with my form definitions a little bit. I looked for an easy way to render params, but haven't quite found the solution. Any helpful suggestions SO?
thanks in advance
Another way is to make use of the helper functions for debugging as described in http://guides.rubyonrails.org/debugging_rails_applications.html
The technique, as previously described is to use params.to_yaml.
Alternatively, in your application.html.erb file put the code
<%= debug(params) if Rails.env.development? %>
after the <%= yield %> call
This will display in the view the params, for example
--- !map:ActiveSupport::HashWithIndifferentAccess
action: edit
controller: contracts
id: "8"
The nice feature is that the information is only output in the Development mode environment, as per the check that is executed to determine which Rails environment is running.
Try <%= params.to_yaml %> in your view
Try using in this view in the view you are posting
<%= params[:name_of_posted_param].each {|param|
params //do something with the param here
} %>
A better way would be to do this in the helper and pass the returning variable in the view.
-R

How to vary a helper called within a Rails 3 layout, depending on the controller

I'm using the same layout for several controllers, and inside this layout I include a menu using a call to a helper, like this:
<%= side_menu %>
What I'd like to do is vary the contents of side_menu depending on the controller that's invoking the layout. In an ideal world, I could define side_menu in application_controller.rb and in other helper files and then the appropriate helper would be selected depending on the controller; in other words, something like this:
# application_helper.rb
def side_menu
"generic menu This goes here"
end
# users_helper.rb
def side_menu
"menu for users goes here"
end
# guests_helper.rb
def side_menu
"menu for guests goes here"
end
This doesn't work because in Rails 3 all helper files are loaded and I have no control over which side_menu will actually be called. It would be great if there were an option to load only application_helper.rb and the controller-specific helper, but there's not one (yet).
What's the best way to vary the content of a helper depending on the controller? I'm currently defining side_menu once in application_helper.rb and then checking to controller to see what to add. This feels wrong, since the problem nearly screams for a subclass-and-override answer -- which I can't do due to the "helper :all" behavior of Rails 3. Suggestions?
You can define this method in controller and add:
helper_method :side_menu
But maybe different solution would be better. I think that you can add _side_menu.html.erb in each controllers view folder and when you call <%= render :partial => 'side_menu' %> it should look for different files depending on current controller (however rememeber to add this file for all controllers).
Or you can mix these two methods. Add this helper method to controller and inside it render right file. This way it is better, because you get some default side menu and it won't crash when there is no side menu partial for a controller.
You can also in layout add <%= yield :side_menu %> and if you want to put something in side menu, just add <% content_for :side_menu do %> bla bla bla <% end %>.

How can I create a "partial" that has its own action?

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:
&lt% #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:
&lt% cache({:variable_id => :whatever}) do %>
&lt% #variable = Variable.find(:whatever) %>
. . .
&lt% end %>
Is there a common model that's being rendered in the main views that you could delegate the variable access to?
&lt%=h #model.variable %>

How do I implement Section-specific navigation in Ruby on Rails?

I have a Ruby/Rails app that has two or three main "sections". When a user visits that section, I wish to display some sub-navigation. All three sections use the same layout, so I can't "hard code" the navigation into the layout.
I can think of a few different methods to do this. I guess in order to help people vote I'll put them as answers.
Any other ideas? Or what do you vote for?
You can easily do this using partials, assuming each section has it's own controller.
Let's say you have three sections called Posts, Users and Admin, each with it's own controller: PostsController, UsersController and AdminController.
In each corresponding views directory, you declare a _subnav.html.erb partial:
/app/views/users/_subnav.html.erb
/app/views/posts/_subnav.html.erb
/app/views/admin/_subnav.html.erb
In each of these subnav partials you declare the options specific to that section, so /users/_subnav.html.erb might contain:
<ul id="subnav">
<li><%= link_to 'All Users', users_path %></li>
<li><%= link_to 'New User', new_user_path %></li>
</ul>
Whilst /posts/_subnav.html.erb might contain:
<ul id="subnav">
<li><%= link_to 'All Posts', posts_path %></li>
<li><%= link_to 'New Post', new_post_path %></li>
</ul>
Finally, once you've done this, you just need to include the subnav partial in the layout:
<div id="header">...</div>
<%= render :partial => "subnav" %>
<div id="content"><%= yield %></div>
<div id="footer">...</div>
Partial render. This is very similar to the helper method except perhaps the layout would have some if statements, or pass that off to a helper...
As for the content of your submenus, you can go at it in a declarative manner in each controller.
class PostsController < ApplicationController
#...
protected
helper_method :menu_items
def menu_items
[
['Submenu 1', url_for(me)],
['Submenu 2', url_for(you)]
]
end
end
Now whenever you call menu_items from a view, you'll have the right list to iterate over for the specific controller.
This strikes me as a cleaner solution than putting this logic inside view templates.
Note that you may also want to declare a default (empty?) menu_items inside ApplicationController as well.
Warning: Advanced Tricks ahead!
Render them all. Hide the ones that you don't need using CSS/Javascript, which can be trivially initialized in any number of ways. (Javascript can read the URL used, query parameters, something in a cookie, etc etc.) This has the advantage of potentially playing much better with your cache (why cache three views and then have to expire them all simultaneously when you can cache one?), and can be used to present a better user experience.
For example, let's pretend you have a common tab bar interface with sub navigation. If you render the content of all three tabs (i.e. its written in the HTML) and hide two of them, switching between two tabs is trivial Javascript and doesn't even hit your server. Big win! No latency for the user. No server load for you.
Want another big win? You can use a variation on this technique to cheat on pages which might but 99% common across users but still contain user state. For example, you might have a front page of a site which is relatively common across all users but say "Hiya Bob" when they're logged in. Put the non-common part ("Hiya, Bob") in a cookie. Have that part of the page be read in via Javascript reading the cookie. Cache the entire page for all users regardless of login status in page caching. This is literally capable of slicing 70% of the accesses off from the entire Rails stack on some sites.
Who cares if Rails can scale or not when your site is really Nginx serving static assets with new HTML pages occasionally getting delivered by some Ruby running on every thousandth access or so ;)
You could use something like the navigation plugin at http://rpheath.com/posts/309-rails-plugin-navigation-helper
It doesn't do sub-section navigation out of the box, but with a little tweaking you could probably set it up to do something similar.
I suggest you use partials. There are a few ways you can go about it. When I create partials that are a bit picky in that they need specific variables, I also create a helper method for it.
module RenderHelper
#options: a nested array of menu names and their corresponding url
def render_submenu(menu_items=[[]])
render :partial => 'shared/submenu', :locals => {:menu_items => menu_items}
end
end
Now the partial has a local variable named menu_items over which you can iterate to create your submenu. Note that I suggest a nested array instead of a hash because a hash's order is unpredictable.
Note that the logic deciding what items should be displayed in the menu could also be inside render_submenu if that makes more sense to you.
I asked pretty much the same question myself: Need advice: Structure of Rails views for submenus? The best solution was probably to use partials.
There is another possible way to do this: Nested Layouts
i don't remember where i found this code so apologies to the original author.
create a file called nested_layouts.rb in your lib folder and include the following code:
module NestedLayouts
def render(options = nil, &block)
if options
if options[:layout].is_a?(Array)
layouts = options.delete(:layout)
options[:layout] = layouts.pop
inner_layout = layouts.shift
options[:text] = layouts.inject(render_to_string(options.merge({:layout=>inner_layout}))) do |output,layout|
render_to_string(options.merge({:text => output, :layout => layout}))
end
end
end
super
end
end
then, create your various layouts in the layouts folder, (for example 'admin.rhtml' and 'application.rhtml').
Now in your controllers add this just inside the class:
include NestedLayouts
And finally at the end of your actions do this:
def show
...
render :layout => ['admin','application']
end
the order of the layouts in the array is important. The admin layout will be rendered inside the application layout wherever the 'yeild' is.
this method can work really well depending on the design of the site and how the various elements are organized. for instance one of the included layouts could just contain a series of divs that contain the content that needs to be shown for a particular action, and the CSS on a higher layout could control where they are positioned.
There are few approaches to this problem.
You might want to use different layouts for each section.
You might want to use a partial included by all views in a given directory.
You might want to use content_for that is filled by either a view or a partial, and called in the global layout, if you have one.
Personally I believe that you should avoid more abstraction in this case.

Resources