Rails rendering a different view depending on the controller - ruby-on-rails

I have a tab navigation page in my rails app which is shared across all of my views. Inside I have a small text area which should change depending on the page that the user is on.
Currently I am doing this by adding a variable to the controller and using it in the render partial path, like so:
class Myapp::WebsitesController < MyappController
def set_up
#page = 'websites/left_text_info'
end
and then in my partial:
<%= render :partial => #page %>
This works but it doesn't feel like the best 'ruby' way of doing things. Can anyone advise on a better way of doing this?
Thanks

You can use controller_name helper method directly in your view and skip the controller part:
<%= render "#{controller_name}/left_text_info" %>
Or if the only thing that change is the content of the textarea, then perhaps the best way is to define a helper method that returns only the content for it, so you don't need multiple partial files that are very similar.
module ApplicationHelper
def text_area_content
case controller_name
when "users"
"content for users"
when "articles"
"content for articles"
else
"other content"
end
end
end

Related

Display navbar on all pages except home page

I want to show two different navbars. One will be displayed, on all pages except home page, when you're logged in. While the other navbar will be displayed just on my landing page.
I am thinking that I will probably need to write an if statement.
If (current user is not logged in) or maybe (current user is viewing home page) do
<nav>Second navbar</nav>
else
<nav>First navbar</nav>
end
I am very new to rails, so I could be wrong. (And yes, I know that's not how to correctly write an if statement in Ruby)
Home page is located at:
home/index.html.erb
I normally do following setup:
create partial shared/_nav_menu.html.erb
inside partial I put logic like:
<% if current_user %>
// nav bar for logged in user
<% else %>
// nav bar for non logged in users
<% end %>
Then inside application.html.erb file I render the partial like this:
<%= render :partial => 'shared/_nav_menu' if show_menu? %>
Inside my application_controller I put logic like this:
def show_menu?
true
end
helper method: show_menu?
If I don't want to show the menu for static_pages then inside static_pages_controller I overwrite show_menu? method to return false.
class StaticPagesController < ApplicationController
def show_menu?
false
end
helper_method: show_menu?
end
You don't have to use exactly this setup but I like this setup because my nav menu logic is kept seperate in partial. All logic required to nav menu lives in this file.
This approach don't bloat my application.html.erb file with lots of if..else.
In the case of two menus, but leaving yourself open to more, I would use a similar-but-slightly-different approach than Reboot's answer.
In the layout:
<%= render :partial => #nav_bar_partial %>
Then in my application controller, define the default nav:
def standard_nav
#nav_bar_partial = "path/to/standard/nav/partial"
end
From there, you can override that nav partial any time you need to (with any partial you want) from your controller
#nav_bar_partial = "path/to/new/nav/partial" if condition_that_requires_a_different_nav
That way, you have a little more flexibility. If for some reason you want to add a third nav bar for some other condition, you can just override the partial elsewhere without changing any of the above code.
You can prepare two layouts, one for the landing page and another for rest of the pages. Take a look at the official documentation: http://guides.rubyonrails.org/layouts_and_rendering.html.

Render show view in a partial - Ruby on Rails

So I have a sidebar in my rails application. Basically, I have a grid full of images. When someone clicks on an image in the grid, I basically want the show view to be displayed in the sidebar. I'm clueless on how to do this.
I've tried copying and pasting the show view's html and erb into my _sidebar.html.erb partial. But I get variable errors. My partial is located in my layout folder. But I can move it if needed.
Here is an image of the application for a better idea of what I'm talking about.
Here's how to do it:
1) Include the sidebar partial in your layout:
#app/views/layouts/application.html.erb
<%= render "shared/sidebar" %>
This calls the _sidebar.html.erb partial in /app/views/shared:
2) Populate the "default" sidebar partial:
#app/views/shared/_sidebar.html.erb
...
The important thing to note here is that partials should never have #instance variables inside.
Partials have locals, which you can pass with the following command:
<%= render "shared/sidebar", locals: { variable: "value" } %>
Partials are meant to run on any part of your web application, and since #instance variables are present for a single "instance" of an object (IE #post won't be available in /users), you can ensure partials are always populated by passing local variables to them.
This is why you received errors when copying your post#show code to your sidebar partial -- the instance variables present for the show action will not be present in other parts of the app.
3) Use JS to pull image objects
When someone clicks on an image in the grid, I basically want the show view to be displayed in the sidebar.
You need to be more specific - do you really want the "show" action to appear, or do you want parts of its functionality?
Either way, you'll be best using JS & ajax to pull the data:
#app/controllers/images_controller.rb
class ImagesController < ApplicationController
layout Proc.new { |controller| !controller.request.xhr? }
end
#app/assets/javascripts/application.js
$(document).on("click", "img", function(e) {
e.preventDefault();
$.get($(this).attr("href"), function(data){
$(".sidebar .image").html(data);
});
});
This will take the rendered images#show action (without layout), and append it to your sidebar partial. This is what you asked for - I can change it if required.
Lets say that your model is called "Image".
In your "images/show.html.erb":
# This is a handy shortcut that will call the 'images/_image' partial.
# Those two lines are exactly the same.
<%= render #image %>
<%= render "images/image", image: #image %>
In your "_sidebar.html.erb":
<div id="sidebar-img"></div>
In your "images/_image.html.erb":
# Code displaying your image, don't use any global variable.
# 'image' is the name of the local variable
In your grid:
# remote: true allows you to do an AJAX call
<%= link_to image, remote: true do %>
# Something like that, I don't know your code
<%= image_tag image.url %>
<% end %>
Create "images/show.js.erb", when clicking on a 'remote :true' link it will call this file.
# set #image to Image.find(params[:id]) in your controller
$("#sidebar-img").html("<%= render #image %>");

Make specific Rails view show certain helpers

How do you make a specific view show a different helper.
module ApplicationHelper
def about_title
%Q{Everything you need!}.html_safe
end
def contact_title
%Q{Contact us!}.html_safe
end
end
I have a partial header that renders in every view but I want to show a different header title without having to edit the views directly (or edit a variable? in the view to show what I want?)
<h1 class="title"><%= about_title %></h1>
What I'm thinking is making an if/else in the helper but I am new to rubyonrails and I'm not sure how is this done.
You need to set the title somewhere. There's a few ways you can handle this. You could use the controller + action name, and set up the titles in i18n.
en:
titles:
home_index: "Welcome!"
session_new: "Login"
Then in your layout:
<title><%= t("titles.#{controller.controller_name}_#{controller.action_name}") %></title>
Another way to do it is using content_for & yield but that means putting code in your views :)

Rails 3, rendering a partial for the given controller if it exists?

In my application.html.erb layout for my app, I want to have a partial that renders if it exists for the given view. for example.
If the visitor is at http://example.com/users/show, I'd want the partial /users/_sidebar.html.erb to render.
But if the visitor were at say, http://example.com/user/locations/san_francisco, I'd want the partial /users/locations/_sidebar.html.erb to render.
So the thing here is that if there were no partial for that controller/action it would render some generic partial in my shared directory, and I'd rather not litter every single view with content_for blocks ya know?
Any ideas guys?
My solution is a bit different. Throw this in your application helper:
def render_partial_if_exists(base_name, options={})
file_name = ::Rails.root.to_s+"/app/views/layouts/_#{base_name}.html.erb"
partial_name = "layouts/#{base_name}"
else_file_name = ::Rails.root.to_s+"/app/views/layouts/_#{options[:else]}.html.erb"
else_partial_name = "layouts/#{options[:else]}"
if File.exists?(file_name)
render :partial => partial_name
elsif (options.key?(:else) and !options[:else].nil? and File.exists?(else_file_name))
render :partial => else_partial_name
end
end
Then in your view:
<%= render_partial_if_exists "page_#{controller.action_name}_sidebar", :else => "page_sidebar" %>
In an edit action, if "layouts/page_edit_sidebar" exists it renders it, otherwise it will render a standby "layouts/page_sidebar"
Sean Behan has a great post on exactly this:
http://seanbehan.com/programming/render-partial-if-file-exists/
I might move it to a helper and tweak it a bit to:
<%= render_sidebar %>
# This method could use either the rescue or the if file exists technique.
def render_sidebar
render(:partial => "/#{controller.name}/sidebar"
rescue
#default side bar
end

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 %>.

Resources