Conditional link display in rails - ruby-on-rails-3

I have a filter bar on my page. The bar should always be in place, however only when I'm on the detail page I want to show a link <- back to list inside of it. Otherwise the filter bar should be empty. What is the most elegant way of doing this in rails 3 or 3.1?
Thanks
Thomas

To return to previous page you can use link_to "Back", :back
To show or hide the link you can use the controller_name and action_name methods with a if/unless conditional.

From your question and the comment, you have the following structure:
application.html.erb:
...
<section id="filter-bar">
<section id="filter"></section>
</section>
I see there two different options how to include your link conditionally:
By doing an if-then in your file application.html.erb
By including a yield with a symbol that denotes the context.
Here is the pseudo-code for that:
solution
application.html.erb:
...
<section id="filter-bar">
<section id="filter">
<% if controller_name == 'user' && action_name == 'show' %>
<%= link_to "Back", :index %>
<% end %>
</section>
</section>
solution
application.html.erb:
...
<section id="filter-bar">
<section id="filter">
<%= yield(:filter) %>
</section>
</section>
view.html.erb:
<%- content_for :filter do %>
<%= link_to "Back", :index %>
<% end %>
...
index.html.erb:
// No content_for section in the file, so it will be empty here.
The first solution is simpler, much more condensed, but all the information if something is included or not is in one file. If that is changed a lot, that may be a hotspot in your application. The second is more object-oriented, but perhaps more to change and think about. But both will working for you.

Related

how to use content_for so that the content shows up in the layout

Am testing the content_for in my rails 3.2 app and following the rails guides but they are specific to the actual files and I cannot seem to get the yield to work:
application.html.erb file:
<!DOCTYPE html>
<html>
<head>
...
</head>
<body>
<%= yield :navigation %> #shouldn't this load the content_for block named :navigation specified in the _main_nav.html.erb partial?
<%= yield %> #this load the index page content
</body>
</html>
I created a layout file _main_nav.html.erb (i know I can render with <%= render 'layouts/header' %> but I am trying to use the content_for instead) The _main_nav.html.erb is:
<% content_for :navigation do %>
<ul>
<li>Home</li>
</ul>
<% end %>
They way I read the RailsGuide http://guides.rubyonrails.org/layouts_and_rendering.html#using-the-content-for-method
this should work. But it does not. I do not get an error. Seems simple but I am stumped.
When I go to my index.html.erb file I would expect to see this result:
Home
I believe what you want to have is have a view that will contain your content_for block. So an example would be if you have the following:
index.html.erb
<% content_for :head do %>
<%= stylesheet_link_tag 'users' %>
#Above this will load the users stylesheet
<% end %>
<h2>Example</h2>
<ul>
<% #users.each do |users| %>
<li><%= user.name %></li>
<% end %>
</ul>
Then to output what inside the users stylesheet we can yield and pass in the symbol of the name of the content_for.
Application.html.erb
<!-DOCTYPE html>
<html>
<head>
<%= yield :head%>
<title>This is my title</title
</head>
<body>
<p>This is a test</p>
<%= yield %>
</html>
So to review whats happening here is that, in my example I am saying I have a users stylesheet that I would like to load into the <head></head> of my application.html.erb. To do this I set the content_for which is a Rails helper and give it the identifier sysmbol which is head which is then called in the application.html.erb where I do yeild :head. So what I am getting my application to do is when the my index.html.erb for that page is being rendered the application.html.erb will load my users stylesheet. Hope this clears things up for you.
Update explanation
To add to this another thing the purpose of combination of using content_for with yield is to allow you to inject data into the application layout from ANY view. So as another example. You could have the following:
<% content_for :title do %> My Title<% end %>
Here when the controller renders the view template and combines it with the application layout, the text My title will be replaced. The yield(:head) makes it easy to add more elements to the specific page if needed. Take a look at the following example:
app/views/layouts/application.html.erb
<% if content_for?(:navbar) %>
<%= yield(:navbar) %>
<% else %>
<%# default navbar %>
<section class="navbar"></section>
<% end %>
app/views/blah/index.html.erb
<% content_for(:navbar) do %>
<section class="navbar"></section>
<% end %>
And a further note not sure how your developing your application or what design framework your using but you could also take a look at Rails-Bootstrap-Navbar. May also be an alternative.
OK, I think I have a solution for this. Your code:
<% content_for :navigation do %>
<ul>
<li>Home</li>
</ul>
<% end %>
should be at the top of the file that is loading. Your _header.html.erb is a partial. If you move this code into views/tasks/new.html.erb then it works as expected.
However, for it to work as you want, then you need to adjust your application.html.erb file:
<p>this is where we should see the "Home" link appear that is defined in _header.html.erb:</p>
<section class="header">
<% render 'layouts/header' %>
<%= yield :navigation %>
</section>
Notice, that I have called the render erb tag without the = sign. This means I don't see the contents of the header partial, but it does load. If you include the = sign then it still works but also renders any other content you may have in the partial.
Note: The render tag has to be above/before the yield tag.

Nivo Slider, showing image one on top of the other (nothing of "sliding")

I'm trying to set up Nivo Slider in a rails app with twitter-bootstrap, the problem I'm facing is tha images appear on top of the other not sliding, any idea how to solve this?
here is my code:
load the nivo slider:
<div class="slider-wrapper theme-default">
<div id="slider" class="nivoSlider">
<% #page.images.each_with_index do |img, index| %>
<%= image_tag img.url, :title => '#htmlcaption' %>
</div>
</div>
<div id="htmlcaption" class="nivo-html-caption">
<%=raw #page.caption_for_image_index(index) %>
</div>
<% end %>
_javascript.html.erb
<%= javascript_include_tag 'application' %>
<%= javascript_include_tag 'jquery.nivo.slider.pack' %>
<%= javascript_include_tag 'jquery.nivo.slider' %>
<script type="text/javascript">
$(window).load(function() {
$('#slider').nivoSlider({
effect: 'fade',
pauseTime: 5000,
directionNav:true,
controlNav:true
});
});
</script>
application.js
//= require jquery
//= require jquery_ujs
//= require twitter/bootstrap
//= require bootstrap
I believe the problem comes from the each loop. If you notice inside the loop you have two closing div tags - just bellow this line <%= image_tag img.url, :title => '#htmlcaption' %>. Therefore you open the divs once, but close then multiple times.
What you can do instead is change slightly the code like:
<div class="slider-wrapper theme-default">
<div id="slider" class="nivoSlider">
<% #page.images.each do |img| %>
<%= image_tag img.url, :title => img.caption_for_image %>
<% end %>
</div>
</div>
Have a look at Nivo Docs. There are further example for alternative caption options.
I found a very easy fix to this issue:
I'm using a legacy CMS and that's inserting image map tags next to some images in the slider (resulting in blank slides). Simply ignoring irrelevant elements seems to work well.
In your jquery.nivo.slider.js file replace line 36
//Find our slider children
Replace this
36 - var kids = slider.children();
with
36 - var kids = slider.children("img,a");
save the change, reload your browser and issue solved.
For more details visit github gilbitron / Nivo-Slider

RoR: how can I paginate all of my users microposts all in one place?

I want the home page to show everyones microposts, but I keep getting errors. I feel like this might be because the microposts have a belong_to has_many relationship with users. But anyways, This is the code for the home page..
<section>
<%= render 'shared/user_info' %>
</section>
<section>
<div id= "purchases">
<%= render 'shared/micropost_form_purchase' %>
</div>
<div id="sales">
<%= render 'shared/micropost_form_sale' %>
</div>
</section>
<ol class="microposts">
<%= render #microposts %>
</ol>
<%= will_paginate #microposts %>
and it gives me this error: 'nil' is not an ActiveModel-compatible object that returns a valid partial path. at the bottom.
I added
def home
#microposts = Micropost.all
end
to the microposts controller.
can anyone help me out? please?
The call to render is looking for a partial view that it can't find. If you're keeping all your partials in views/shared/, then do you have a views/shared/micropost.html.erb for it to render?

Is it possible to pass html elements into a partial?

I have a partial that contains a header, a subheader and potentially one or more buttons. It is used on many different pages. Often the pages don't need buttons, so I just pass in the header and an optional subheader to the partial. However sometimes the pages need one or more buttons and the only way I've managed to allow for an arbitrary number of buttons to be passed in is using content_for. My partial looks like this:
<% if defined? page_title %>
<header class="pageHeader">
<div class="page-details">
<h3><%= page_title %></h3>
<% if defined? page_subtitle %>
<p><%= page_subtitle %></p>
<% end %>
</div>
<ul class="crud-menu nav-pills">
<%= content_for :page_header_buttons %>
</ul>
</header>
<% end %>
This use of content_for nasty. Is there any way I can pass the list items / buttons into this partial? How else could I deal with this situation?
You could transform this partial into a layout:
<% if defined? page_title %>
<header class="pageHeader">
<div class="page-details">
<h3><%= page_title %></h3>
<% if defined? page_subtitle %>
<p><%= page_subtitle %></p>
<% end %>
</div>
<ul class="crud-menu nav-pills">
<%= yield %>
</ul>
</header>
<% end %>
And you would render it like that:
<%= render layout: "your_partial_above", locals: { page_title: "page title } do %>
<%= render "partial_with_your_buttons" %>
<% end %>

Refactoring - Chapter 11, Exercise 3 Rails Tutorial 2nd Edition

Anyone else working through Chapter 11 Exercises for Michael Hartl's Rails Tutorial 2nd Edition?
Chapter 11, Exercise 3 asks:
Refactor Listing 11.31 by adding partials for the code common to the following/followers pages, the Home page, and the user show page.
I'm not seeing anything worth refactoring in the homepage, user show page, or the show_follow page
If anyone came up with something worthwhile for this exercise, would love to know.
Thanks!
You can refactor the first block of code from Listing 11.31:
<section>
<%= gravatar_for #user %>
<h1><%= #user.name %></h1>
<span><%= link_to "view my profile", #user %></span>
<span><b>Microposts:</b> <%= #user.microposts.count %></span>
</section>
because it is essentially the same as the views\shared_user_info.html.erb partial used on the home page (Listing 10.32). Therefore, you can replace the block of code above with this:
<%= render 'shared/user_info' %>
Note that you will also need to add <% #user ||= current_user %> to the top of the views\shared_user_info.html.erb partial (which is the same as what was necessary to add to the stats partial in Listing 11.20).
Additionally, there is some duplication (though not exact duplication) between the feed_item + feed partials with the user + micropost partials, where depending on which page is being displayed (follow_show, home, or profile) there are one or more elements being listed (name, gravatar, admin delete link, micropost content, micropost time stamp, and micropost delete link). Those could probably be refactored too to eliminate the feed_item+feed partials and replace them with a combination of the user + micropost partials depending on the page.
I just worked through this exercise and found a solution that works.
First I changed around app/views/shared/_user_info.html.erb to use the #user variable if it is set, and the current_user variable otherwise.
app/views/shared/_user_info.html.erb:
<% if #user %>
<%= link_to gravatar_for(#user, size: 52), #user %>
<h1>
<%= #user.name %>
</h1>
<span>
<%= link_to "view my profile", #user %>
</span>
<span>
<%= pluralize(#user.microposts.count, "micropost") %>
</span>
<% else %>
<%= link_to gravatar_for(current_user, size: 52), current_user %>
<h1>
<%= current_user.name %>
</h1>
<span>
<%= link_to "view my profile", current_user %>
</span>
<span>
<%= pluralize(current_user.microposts.count, "micropost") %>
</span>
<% end %>
Then I replaced the corresponding information in app/views/users/show_follow.hmtl.erb with the partial _user_info.html.erb
app/views/users/show_follow.hmtl.erb:
<div class="row">
<aside class="span4">
<section>
<%= render 'shared/user_info' %>
</section>
<section>
<%= render 'shared/stats' %>
<% if #users.any? %>
<div class="user_avatars">
<% #users.each do |user| %>
<%= link_to gravatar_for(user, size: 30), user %>
<% end %>
</div>
<% end %>
</section>
</aside>
<div class="span8">
<h3><%= #title %></h3>
<% if #users.any? %>
<ul class="users">
<%= render #users %>
</ul>
<%= will_paginate %>
<% end %>
</div>
</div>
I hope this answer helps anyone going through M. Hartl's tutorial.