Rails: How should I adjust the 'each' method under a nest structure? - ruby-on-rails

Before putting pinunder the nest structure of group,
One of the view looked like this:
<div class="transitions-enabled" id="pins">
<% #pins.each do |pin| %>
<div class="box panel panel-default">
<%= link_to (image_tag pin.image.url), pin %>
<div class="panel-body">
<h2><%= link_to pin.title, pin %></h2>
</div>
<div class="footer">
<div class="row footer-all">
<div class="col-md-6">
<p class="user">Submitted by <%= pin.user.username %></p>
</div>
<div class="col-md-6">
<div class="btn-group like_btn">
<% if user_signed_in? %>
<% if current_user.voted_up_on?(pin) %>
<%= link_to unlike_pin_path(pin), method: :put, class: "btn btn-default" do %>
<span class='glyphicon glyphicon-heart'></span>
<%= pin.get_upvotes.size %>
<%end%>
<% else %>
<%= link_to like_pin_path(pin), method: :put, class: "btn btn-default" do %>
<span class='glyphicon glyphicon-heart'></span>
<%= pin.get_upvotes.size %>
<%end%>
<% end %>
<% else %>
<div class="like_btn">
<span class='glyphicon glyphicon-heart'></span>
<%= pin.get_upvotes.size %>
</div>
<% end %>
</div>
</div>
</div>
</div>
</div>
<%end%>
How should I adjust it after I put it under group (I'll mark the code which I think needed to change with'* *'):
Group has_many pins
Pin belongs_to group
<div class="transitions-enabled" id="pins">
<% #pins.each do |pin| %>
<div class="box panel panel-default">
<%= link_to (image_tag pin.image.url), *pin* %>
<div class="panel-body">
<h2><%= link_to pin.title, *pin* %></h2>
</div>
<div class="footer">
<div class="row footer-all">
<div class="col-md-6">
<p class="user">Submitted by <%= pin.user.username %></p>
</div>
<div class="col-md-6">
<div class="btn-group like_btn">
<% if user_signed_in? %>
<% if current_user.voted_up_on?(*pin*) %>
<%= link_to unlike_group_pin_path(*pin*), method: :put, class: "btn btn-default" do %>
<span class='glyphicon glyphicon-heart'></span>
<%= pin.get_upvotes.size %>
<%end%>
<% else %>
<%= link_to like_group_pin_path(*pin*), method: :put, class: "btn btn-default" do %>
<span class='glyphicon glyphicon-heart'></span>
<%= pin.get_upvotes.size %>
<%end%>
<% end %>
<% else %>
<div class="like_btn">
<span class='glyphicon glyphicon-heart'></span>
<%= pin.get_upvotes.size %>
</div>
<% end %>
</div>
</div>
</div>
</div>
</div>
<%end%>

After stating that your objective is to use this view file to filter the pins depending on its group, then I can think of two approaches for this.
Use nested resources. (RailsCast)
This is a little trickier than 2. but it is much more organised, and RESTful
You could check the RailsCast if you are interested. Otherwise, I will just go explaining 2. as it's simpler.
Use params[:group_id] to filter the pins.
In the PinsController, add the following at the very end of the method where this view is rendered.
#group = Group.where(id: params[:group_id]).first
#pins = #pins.where(group: #group) if #group
Then in your view files, you'll just have to tweak your links to specify the group_id parameter. If this view file is associated to the #index method, then change
<%= link_to 'Link', pins_path %>
Into
<%= link_to 'Link', pins_path(group_id: 1) %>
Change 1 accordingly as you wish. If you don't specify the parameter group_id, the link will still work but you will notice that the page will show all pins, and not filtered by group.

Thanks for everyone's help, I think I find the problem:
The view should be changed into:
<div class="transitions-enabled" id="pins">
<% #pins.each do |pin| %>
<div class="box panel panel-default">
<%= link_to (image_tag pin.image.url), group_pin_path(#group, pin)
%>
<div class="panel-body">
<h2><%= link_to pin.title, group_pin_path(#group, pin) %></h2>
</div>
<div class="footer">
<div class="row footer-all">
<div class="col-md-6">
<p class="user">Submitted by <%= pin.user.username %></p>
</div>
<div class="col-md-6">
<div class="btn-group like_btn">
<% if user_signed_in? %>
<% if current_user.voted_up_on?(#group, pin) %>
<%= link_to unlike_group_pin_path(#group, pin), method: :put, class: "btn btn-default" do %>
<span class='glyphicon glyphicon-heart'></span>
<%= pin.get_upvotes.size %>
<%end%>
<% else %>
<%= link_to like_group_pin_path(#group, pin), method: :put, class: "btn btn-default" do %>
<span class='glyphicon glyphicon-heart'></span>
<%= pin.get_upvotes.size %>
<%end%>
<% end %>
<% else %>
<div class="like_btn">
<span class='glyphicon glyphicon-heart'></span>
<%= pin.get_upvotes.size %>
</div>
<% end %>
</div>
</div>
</div>
</div>
</div>
<%end%>
And remember to state #group = Group.find(params[:group_id]) in the PinController, this is very important.

Related

Nil:nil class error on each loop when Form to build object loaded on page first

I have a form on a page that is building a “tip” for a “guide”. Below the form, I am running an each loop over all the #guide.tips. I keep getting an error as the each loop is loading the forms blank object as it sees it as a tip. I’ve currently solved the problem by using jQuery to inject the form after page load, but there has to be a better solution.
Each Loop on Guide.html.erb
<% if !#guide.tips.blank? %>
<% #guide.tips.each do |tip| %>
<div class="row mx-1">
<div class="col-md-3 border-right">
<div class="float-left">
<%= image_tag avatar_url(tip.user), class: "float-left text-left align-middle rounded img-fluid mx-3", width: "30%" %>
<p><%= tip.user.fullname %></p>
</div>
<div class="float-right mr-3">
<%= link_to like_tip_path(tip), method: :put do %>
<div class="fas fa-angle-up"></div>
<%= tip.get_upvotes.size %>
<% end %><br/>
<%= link_to dislike_tip_path(tip), method: :put do %>
<div class="fas fa-angle-down"></div>
<%= tip.get_downvotes.size %>
<% end %>
</div>
</div>
<div class="col-md-8 ml-3">
<h6><%= tip.title %> -<span class="ml-1"><small><%= tip.created_at.strftime("%A, %d %b %Y %l:%M %p")%></small></span></h6>
<%= tip.tip %>
</div>
</div><hr/>
<% end %>
<% end %>
Tips_Controller.rb
def new
#guide = Guide.find(params[:guide_id])
#tip = Tip.new
end
def edit
end
def create
#guide = Guide.find(params[:guide_id])
params[:tip][:user_id] = current_user.id
#tip = #guide.tips.create!(tip_params)
redirect_to guide_path(#guide)
end
Tip Form Partial
<%= form_for([#guide, #guide.tips.build]) do |f| %>
<div class="form-group row">
<div class="col-sm-12">
<p class="text-left">Tip Title</p>
<%= f.text_field :title, placeholder: "Enter Title", class: "form-control" %>
</div>
<div class="col-sm-12 mt-2">
<p class="text-left">Your Tip</p>
<%= f.text_area :tip, placeholder:"What's your tip for this travel guide?", class: 'form-control' %>
</div>
</div>
<div class="form-group row">
<div class="col-md">
<%= f.submit 'Submit', class: 'btn btn-primary btn-block' %>
</div>
</div>
<% end %>
Here is another solution that does not separate the logic between the controller and the view and cleans up your empty array statement for your loop
Each Loop on Guide.html.erb
<% #guide.tips.each do |tip| %>
<div class="row mx-1">
<div class="col-md-3 border-right">
<div class="float-left">
<%= image_tag avatar_url(tip.user), class: "float-left text-left align-middle rounded img-fluid mx-3", width: "30%" %>
<p><%= tip.user.fullname %></p>
</div>
<div class="float-right mr-3">
<%= link_to like_tip_path(tip), method: :put do %>
<div class="fas fa-angle-up"></div>
<%= tip.get_upvotes.size %>
<% end %><br/>
<%= link_to dislike_tip_path(tip), method: :put do %>
<div class="fas fa-angle-down"></div>
<%= tip.get_downvotes.size %>
<% end %>
</div>
</div>
<div class="col-md-8 ml-3">
<h6><%= tip.title %> -<span class="ml-1"><small><%= tip.created_at.strftime("%A, %d %b %Y %l:%M %p")%></small></span></h6>
<%= tip.tip %>
</div>
</div><hr/>
<% end unless #guide.tips.blank? %>
Tip Form Partial
By creating the Tip from outside the association (i.e. not using build), it will not be loaded into the class variable's children
<%= form_for([#guide, Tip.new(guide: #guide)]) do |f| %>
<div class="form-group row">
<div class="col-sm-12">
<p class="text-left">Tip Title</p>
<%= f.text_field :title, placeholder: "Enter Title", class: "form-control" %>
</div>
<div class="col-sm-12 mt-2">
<p class="text-left">Your Tip</p>
<%= f.text_area :tip, placeholder:"What's your tip for this travel guide?", class: 'form-control' %>
</div>
</div>
<div class="form-group row">
<div class="col-md">
<%= f.submit 'Submit', class: 'btn btn-primary btn-block' %>
</div>
</div>
<% end %>
Another Example / Q&A
Using the structure you already have you could do:
<% if #guide.tips.count > 1 %> (assuming this will always be shown with an empty "build" tip)
or you can use:
<% next unless tip.persisted? %>
inside the loop, before the actual form.
You also don't need the blank? check as an .each on an empty enumerator simply won't execute the block, and as long as there's a has_many relationship between guide and tips it will always yield a collection proxy.
I would write it as:
<% #guide.tips.each do |tip| %>
<% next unless tip.persisted? %>
<div class="row mx-1">
<div class="col-md-3 border-right">
...
<% end %>

Lightbox with Rails

So I am trying to use Lightbox2 on my application. I installed the gem and followed all the steps, but having trouble figuring out where to call it in the application.
This is my post index
<div class="container">
<div id="profuploads">
<div id="posts" class="transitions-enabled">
<% #posts.each do |post| %>
<div class="box panel panel-default">
<%= link_to image_tag(post.image.url(:medium)), post %>
<div class="panel-body">
<strong><%= post.user.username if post.user %></strong><br/>
<%= post.description %>
<% if post.user == current_user %>
<div class="actions">
<%= link_to 'Edit', edit_post_path(post) %>
<%= link_to 'Destroy', post, method: :delete, data: { confirm: 'Are you sure?' } %>
</div>
<% end %>
</div>
</div>
<% end %>
</div>
</div>
</div>
This is my post show
<div class="row">
<div class="col-md-offset-1 col-md-10">
<div class="panel panel-default">
<div class="panel-heading center">
<%= image_tag #post.image.url, height: '300' %>
</div>
<div class="panel-body">
<p><strong><%= link_to(#post.user.username.capitalize, user_path(#post.user.id)) if #post.user %></strong></p>
<p><%= #post.description %></p>
<div class="votes">
<strong>VIEWS</strong>
<%= #post.hits %>
<div class="votes">
<%= link_to like_post_path(#post), method: :put do%>
<button type="button" class="btn btn-info" aria-label="Left Align">
<span class="glyphicon glyphicon-thumbs-up glyphicon-align-center" aria-hidden="true"></span>
<span class="badge"><%= #post.get_upvotes.size %></span>
</button>
<%end%>
</div>
<% if #post.user == current_user %>
<%= link_to 'Edit', edit_post_path(#post) %>
<% end %>
</div>
</div>
</div>
</div>
With Lightbox do I need to just git rid of my post show page altogether?
Lightbox is a javascript library which needs proper html markup in order to do it's work. Your show view looks good except it does not include the markup Lightbox looks for.
From Lightbox Getting Started guide:
Add a data-lightbox attribute to any image link to enable Lightbox. For the value of the attribute, use a unique name for each image. For example:
Image #1
When Lightbox initializes, it looks for any image tags that contain data-lightbox attribute and hooks its handlers to them. You need to provide this attribute:
<%= image_tag #post.image.url, height: '300', "data-lightbox" => #post.image.url %>
This should make Lightbox pick up your images.

bootstrap grid system not formatting correctly without commenting out a class='col-md-6'

I would like to have user who have not created a profile to be directed to a page that instructs them to do so.
If user has not created a profile, I would like the bootstrap well to go across the page. I can only get it to work by commenting out line 7 (or the first: div class="col-md-6") , which messes up the interface if user has created a profile.
<div class="jumbotron text-center">
<h1>Welcome to Jr. Dev Mentoring</h1>
<h3>Harnessing the Power of Mentorship <br>To Build A Community of Work Ready Jr. Devs.</h3>
</div>
<div class="row">
<% if user_signed_in? %>
<div class="col-md-6">
<div class="well">
<h2 class="text-center">Your Profile</h2>
<% if current_user.profile %>
<%= link_to "Edit your profile", "#", class: 'btn btn-default btn-lg btn-block' %>
<%= link_to "View your profile", user_path(current_user), class: 'btn btn-default btn-lg btn-block' %>
</div>
</div>
<div class="col-md-6">
<% if current_user.plan.name == "mentor" %>
<%= render partial: "pages/mentor" %>
<% else %>
<%= render partial: "pages/mentee" %>
<% end %>
</div>
<% else %>
<div class='container'>
<div class='row'>
<div class='col-md-8 col-md-offset-2'>
<p class='text-center'>Create your profile so that you can share your information with the Jr. Dev Mentoring community.</p>
<%= link_to "Create your profile", new_user_profile_path(current_user), class: 'btn btn-default btn-lg btn-block'%>
</div>
</div>
</div>
<% end %>
<% else %>
<div class="col-md-6">
<div class="well">
<h2 class="text-center">Mentee</h2>
<h4 class="text-center">Sign up for free to gain access to our community of mentors.</h4>
<br/>
<%= link_to "Sign Up", new_user_registration_path(plan: #mentee_plan.id), class: 'btn btn-primary btn-lg btn-block' %>
</div>
</div>
<div class="col-md-6">
<div class="well">
<h2 class="text-center">Mentor</h2>
<h4 class="text-center">Sign up for free to lend your expertise and support!</h4><br>
<%= link_to "Sign Up", new_user_registration_path(plan: #mentor_plan.id), class: 'btn btn-success btn-lg btn-block' %>
</div>
</div>
<% end %>
</div>
Here you are: You had a slight mis-arrangement around line 7, :).
<div class="jumbotron text-center">
<h1>Welcome to Jr. Dev Mentoring</h1>
<h3>Harnessing the Power of Mentorship <br>To Build A Community of Work Ready Jr. Devs.</h3>
</div>
<div class="row">
<% if user_signed_in? %>
<% if current_user.profile %>
<div class="col-md-6">
<div class="well">
<h2 class="text-center">Your Profile</h2>
<%= link_to "Edit your profile", "#", class: 'btn btn-default btn-lg btn-block' %>
<%= link_to "View your profile", user_path(current_user), class: 'btn btn-default btn-lg btn-block' %>
</div>
</div>
<div class="col-md-6">
<% if current_user.plan.name == "mentor" %>
<%= render partial: "pages/mentor" %>
<% else %>
<%= render partial: "pages/mentee" %>
<% end %>
</div>
<% else %>
<div class='container'>
<div class='row'>
<div class='col-md-8 col-md-offset-2'>
<p class='text-center'>Create your profile so that you can share your information with the Jr. Dev Mentoring community.</p>
<%= link_to "Create your profile", new_user_profile_path(current_user), class: 'btn btn-default btn-lg btn-block'%>
</div>
</div>
</div>
<% end %>
<% else %>
<div class="col-md-6">
<div class="well">
<h2 class="text-center">Mentee</h2>
<h4 class="text-center">Sign up for free to gain access to our community of mentors.</h4>
<br/>
<%= link_to "Sign Up", new_user_registration_path(plan: #mentee_plan.id), class: 'btn btn-primary btn-lg btn-block' %>
</div>
</div>
<div class="col-md-6">
<div class="well">
<h2 class="text-center">Mentor</h2>
<h4 class="text-center">Sign up for free to lend your expertise and support!</h4><br>
<%= link_to "Sign Up", new_user_registration_path(plan: #mentor_plan.id), class: 'btn btn-success btn-lg btn-block' %>
</div>
</div>
<% end %>
</div>

Rails partial view repeat display

Here is part of my index.html
<div class="col-md-8">
<% #books.each do |book| %>
<div class="row">
<div class="col-md-4">
<%= image_from_amazon(book.amazon_id) %>
</div>
<div class="col-md-8">
<h3 class = "text-info">
<%= book.title %>
</h3>
<br>
<em class ="text-muted">
written by <%= book.author %>
</em>
<br>
<br>
<p>
<%= book.description %>
</p>
<% book.genres.each do |genres| %>
<span class="label label-primary">
<%= genres.name %>
</span>
&nbsp
<% end %>
</div>
</div>
<% end %>
</div>
Basically, it will display 3 books, and it works fine.
Then, I move that code into _book.html.erb and edit above code into
<%= render #books %>
However, it repeat 3 times, that is, it display 9 books. And the sequence is [1st,2nd,3rd] [1st,2nd,3rd] [1st,2nd,3rd] like this picture.
Update
update index.html.erb
<div class="clearfix">
<div class="col-md-12">
<%= render #books %>
<div class="col-md-4">
<h3>Genre (Click to filter books)</h3>
<br>
<li>
<span class = 'label label-danger'>
<%= link_to "No filter" ,books_path, style: 'color:#FFFFFD' %>
</span>
<br>
<br>
</li>
<% #genres.each do |genres| %>
<li>
<span class = 'label label-primary' style="color:#FFFFFD">
<%= link_to genres.name ,books_path(filter: genres.name),style: 'color:#FFFFFD' %>
</span>
</li>
<br>
<% end %>
</div>
</div>
<!-- clearfix -->
</div>
Try the following:
<div class="col-md-8">
<%= render #books %>
</div>
And make sure <% #books.each do |book| %> and its <% end %> tag aren't in the partial.
Rendering Collections Docs
Edit
#index.html.erb
<div class="col-md-8">
<%= render #books %>
</div>
# _book.html.erb
<div class="row">
<div class="col-md-4">
<%= image_from_amazon(book.amazon_id) %>
</div>
<div class="col-md-8">
<h3 class = "text-info">
<%= book.title %>
</h3>
<br>
<em class ="text-muted">
written by <%= book.author %>
</em>
<br>
<br>
<p>
<%= book.description %>
</p>
<% book.genres.each do |genres| %>
<span class="label label-primary">
<%= genres.name %>
</span>
&nbsp
<% end %>
</div>
</div>

Rails syntax error, unexpected keyword_ensure, expecting keyword_end

I'm trying to get two different types of tags working using the acts_as_taggable_on gem. I was following this link. I'm getting this error:
syntax error, unexpected keyword_ensure, expecting keyword_end
yntax error, unexpected end-of-input, expecting keyword_end
The error says the problem is line 92 of my show.html.erb, but when I put and <% end %> there, it doesn't fix it.
show.html.erb
<%- title "#{#artwork.title} — a #{#artwork.category.downcase} by Peter Bentley"%>
<% if user_signed_in? %>
<div class="row">
<div class="col-md-12">
<%= link_to 'Edit', edit_artwork_path(#artwork) %> |
<%= link_to 'Artworks Table', admin_path %>
</div>
</div>
<% end %>
<div class="row">
<div class="col-md-8">
<%= image_tag(#artwork.image.url, :class => 'img-responsive') %>
</div>
<div class="col-xs-12 col-md-4">
<p class="field-label">Title</p>
<h1><%= #artwork.title %></h1>
</div>
<div class="col-xs-6 col-sm-3 col-md-4">
<p class="field-label">Medium</p>
<h3><%= #artwork.medium %></h3>
</div>
<% unless #artwork.date.blank? %>
<div class="col-xs-6 col-sm-3 col-md-2">
<p class="field-label">Date</p>
<h3><%= #artwork.date.strftime("%b %d %Y") %></h3>
</div>
<% end %>
<% unless #artwork.height.blank? | #artwork.width.blank?%>
<div class="col-xs-6 col-sm-3 col-md-4">
<p class="field-label">Size</p>
<h3><%= #artwork.height %> x <%= #artwork.width %> in.</h3>
</div>
<% end %>
<div class="col-xs-6 col-sm-3 col-md-2">
<p class="field-label">Genre</p>
<h3><%= #artwork.genre %></h3>
</div>
<div class="col-xs-6 col-sm-3 col-md-2">
<p class="field-label">Category</p>
<h3><%= #artwork.category %></h3>
</div>
<% unless #artwork.availability.blank? %>
<div class="col-xs-12 col-sm-3 col-md-4">
<% if #artwork.availability == 'Available for purchase' %>
<p class="field-label">Availability</p>
<h3><%= #artwork.availability %></h3>
<%= link_to "Add to Inquiry List", root_path, class: "btn btn-primary" %>
<% else %>
<p class="field-label">Availability</p>
<h3><%= #artwork.availability %></h3>
<% end %>
</div>
<% end %>
<% unless #artwork.series.blank? %>
<div class="col-xs-6 col-sm-6 col-md-4">
<p class="field-label">Series</p>
<% #artwork.series.each do |series| %>
<span class="tags">
<%= link_to series.name, series_url(:series => series.name) %>
</span>
</div>
<% end %>
<% unless #artwork.tags.blank? %>
<div class="col-xs-6 col-sm-6 col-md-4">
<p class="field-label">Tags</p>
<% #artwork.tags.each do |tag| %>
<span class="tags">
<%= link_to tag.name, tagged_url(:tag => tag.name) %>
</span>
</div>
<% end %>
</div> <!-- end of 'row' div -->
<div class="fixed-prev-next">
<div class="btn-group" role="group" aria-label="...">
<%= link_to "Previous", #artwork.previous, :class => "btn btn-default" if #artwork.previous.present? %>
<%= link_to "Next", #artwork.next, :class => "btn btn-default" if #artwork.next.present? %>
</div>
</div>
<% end %>
artworks_controller.erb has
def index
if params[:tag]
#artworks = Artwork.tagged_with(params[:tag])
else
#artworks = Artwork.all
end
end
def tagged
if params[:tag].present?
#artworks = Artwork.tagged_with(params[:tag])
else
#artworks = Artwork.all
end
end
def series
if params[:series].present?
#artworks = Artwork.tagged_with(params[:series])
else
#artworks = Artwork.all
end
end
and private method that permits
:tag_list, :tag, :series_list, :series
artwork.rb has
acts_as_taggable
acts_as_taggable_on :tags, :series
What am I doing wrong?
You are failing to close 2 of your loops with an <% end %>.
<% unless #artwork.series.blank? %>
<div class="col-xs-6 col-sm-6 col-md-4">
<p class="field-label">Series</p>
<% #artwork.series.each do |series| %>
<span class="tags">
<%= link_to series.name, series_url(:series => series.name) %>
</span>
<%# Need end here, as illustrated on the next line. %>
<% end %>
</div>
<% end %>
<% unless #artwork.tags.blank? %>
<div class="col-xs-6 col-sm-6 col-md-4">
<p class="field-label">Tags</p>
<% #artwork.tags.each do |tag| %>
<span class="tags">
<%= link_to tag.name, tagged_url(:tag => tag.name) %>
</span>
<%# Need end here, as illustrated on the next line. %>
<% end %>
</div>
<% end %>
Take more care about how you're indenting your code. It matters and helps you to more easily prevent and debug syntax problems like this.

Resources