I am new to rails, and I was wondering if there was a simple (or not simple) way to indent every child of a DPS?
I have a model called "Comment" that has_many :comments and belongs_to :comment. In my view I've implemented a DPS to display each comment and each comment on that comment, and each comment on that comment, etc.
My code looks like this:
<div class=feed>
<% #comments.each do |comment| %>
<% if comment.comment_id == nil # display all original comments %>
<!-- subject -->
<div class="subject">
<%= comment.subject %>:
</div>
<!-- create array of replies -->
<% replies = Array.new %>
<% replies.push(comment) %>
<% while replies.any? %>
<% reply = replies[0] %>
<% replies.delete_at(0) %>
<!--- name -->
<div class="comment">
<%= User.find(reply.user_id).name %>
<!-- comment -->
<%= reply.body %>
<% if user_signed_in? %>
<%= link_to "reply", new_comment_comment_path(reply.id) %>
<% end %>
</div>
<% reply.comments.each do |further_replies| %>
<% replies.push(further_replies) %>
<% end %>
<br>
<% end %>
<br>
<% end %>
<% end %>
</div>
where I push each comment onto "replies" and visit each reply one by one.
Is there a good way to indent each child comment?
Thanks!
You can use act_as_tree structure, in that case your model will be like -
class Comment
has_many :replies, class_name: 'Comment', foreign_key :comment_id
belongs_to :user
end
Your html code will be very simple in that case like
<div class=feed>
<% #comments.each do |comment| %>
<div class="subject">
<%= comment.subject %>:
</div>
<% comment.replies.each do |reply| %>
<div class="comment">
<%= reply.user..name %>
<%= reply.body %>
<% if user_signed_in? %>
<%= link_to "reply", new_comment_comment_path(reply.id) %>
<% end %>
</div>
<br>
<% end %>
<br>
<% end %>
</div>
I figured out a different approach that worked well. I implemented a recursive depth first search in "CommentsController" that returned a hash of { comments => amount_to_indent }, where comments are in the order that they were visited. In the view file iterated though the hash, using comment and amount_of_indent where appropriate.
class CommentsController < ApplicationController
def index
#comments = Comment.all
# depth first search
#visited = Hash.new
#comments.each do |comment|
if !comment.comment_id # has not parent comment
indent = 0
comment_array = DFS(comment, #visited, indent)
end
end
end
def DFS(comment, visited, indent)
visited[comment] = indent # add elements in order in which they are visited
comment.comments.each do |reply|
DFS(reply, visited, indent + 4)
end
visited
end
And in the view file:
<div class="feed">
<% #visited.each do |reply, indent| %>
<!-- display subject of all parent comments -->
<div class="subject">
<% if !reply.comment_id? %>
<%= reply.subject %>:
<% end %>
</div>
<!--- name and content -->
<div class="comment">
<!-- preceed comment with indent -->
<%= raw((' ') * indent) %>
<%= User.find(reply.user_id).name + ":" + reply.body %>
<% if user_signed_in? %>
<%= link_to "reply", new_comment_comment_path(reply.id) %>
<!--%= link_to 'delete', response, method: :delete, data: { confirm: 'Are you sure?' } %-->
<% end %>
</div>
<% end %>
</div>
If anyone runs into the same issue I did!
Related
I have one to many relationship(oferta have many sigs) and I want to show the last three sigs from all the oferta
I tried this code but it show the last 3 sigs from each oferta
In home index.erb
<% #oferta.each do |o| %>
<% if o.sigs.exists? %>
<% for item in o.sigs.order("created_at asc").last(3).each %>
<div class="col-md-4 col-sm-4">
<div class="coll">
<br>
<%= link_to item do %>
<%= image_tag item.image.url(), skip_pipeline: true ,id: "img",height: "200px"%>
<% end %>
<h4><%=link_to item.name,item %></h4>
<p id="comment"><%= item.comment %></p>
<%= link_to "read more..", item %>
<p id="price"><%= item.price %></p>
</div>
</div>
<% end %>
<% end %>
<% end %>
In the controller
def index
#oferta = Ofertum.unscoped.first(3)
end
In ofertum model
has_many :sigs
In sig model
belongs_to :ofertum
You can do it in both ways,
#last_3_sigs = Sigs.last(3)
for getting latest records first use this
#last_3_sigs = Sig.order(created_at: :desc).limit(3)
I am working on a RAILS application where I create a view which lists all available resources of a given model species.rb.
The view partial is:
<% i= #s
for species in #species %>
<%= species.name %>, <%= species.author.surname %> <%= species.author.initial_name %>
<% i -= 1
end %>
Some of the resources species have an related article, others have only the name. I would like to loop through the partial and add a link only to the entries which have an associated article.
Something like: add link if species.article is present else just put species.name without link + loop through it for all entries.
How can I do this?
UPDATE:
Thanks to #jvillian and #fool-dev I was able to progress. In my case I wanted to add a link if the resource has a description in a description row of its table.
<% #species.each do |species| %>
<div class="entry">
<p><i><%= link_to_if(species.txtlandscape.present?, "#{species.name}, #{species.author.surname}, #{species.author.initial_name}. 2014", :controller => 'projects', :action => 'show', :id => species) %></i></p>
</div>
<% end %>
Now that a link is added I was wondering if it can be used to load a partial to a target such as in, where ArticleRequest is a JS function I have:
<% # species.each do | species | %>
<div id="species-<%= species.id %>" class="species-entry">
<a onClick="ArticleRequest('/species/show/<%= species.id %>', 'species-<%= species.id %>');">
<p><%= species.name %></p>
</a>
</div>
<% end %>
Until I find a way to do this with link_to_if, I will use something like:
<% for species in #species %>
<% if species.txtlandscape.present? %>
<a onClick="ArticleRequest('/species/show/<%= species.id %>', 'species-<%= species.id %>');">
<p><%= species.name %>, <%= species.author.surname %> <%= species.author.initial_name %></p>
</a>
<% else %>
<p><%= species.name %>, <%= species.author.surname %> <%= species.author.initial_name %></p>
<% end %>
<% end %>
According to the docs, it seems you should be able to do:
<% #species.each do |specie| %>
<%= link_to_if(specie.article, specie.name, specie_article_path(specie.article)) %>
<% end %>
I made the path name up, you'll have to make that match your actual routes.
BTW, this:
for species in #species
Is super non-idiomatic.
You can do this, see the below
<% for species in #species %>
<% if species.article.present? %> #=> I thin it will be articles because table name is articles, anyway, you know better
<%= link_to species.name, link_path(species.article) %>, #=> on the link_path it will be your proper link just replace this
<% else %>
<%= species.name %>,
<% end %>
<%= species.author.surname %> <%= species.author.initial_name %>
<% end %>
You can do this with Rails each method like below
<% #species.each do |species| %>
<% if species.article.present? %> #=> I thin it will be articles because table name is articles, anyway, you know better
<%= link_to species.name, link_path(species.article) %>, #=> on the link_path it will be your proper link just replace this
<% else %>
<%= species.name %>,
<% end %>
<%= species.author.surname %> <%= species.author.initial_name %>
<% end %>
Or you can use link_to_if it is also most easier to understand
<% #species.each do |species| %>
<%= link_to_if(species.article.present?, "#{species.name},", link_path(species.article)) %>
<%= species.author.surname %> <%= species.author.initial_name %>
<% end %>
Hope it will help.
I'm trying to follow Ryan Bates Polymorphic association tutorial in order to put some comments to my site.
The thing is I have nested resources:
#Nesting Resources
resources :users do
resources :photos do
resources :comments
resources :tags
end
end
So I'm getting an error in my view (photos/show)
undefined method `each' for nil:NilClass
I suppose the problem is in my controller, with comments, that is not defined correctly, but since I have nested resources, I don't know how to do it.
Photos Controller
def show
#photo = Photo.friendly.find(params[:id])
#user = #photo.user
#commentable = #photo
#comments = #commentable.comments
#comment = Comment.new
end
New Comment Partial
<h2>Comments</h2>
<% if #comments.any? %>
<%= render "comments/comments" %>
<% else %>
Todavía no hay comentarios
<% if user_signed_in? %>
<%= render "comments/form" %>
<% end %>
<% end %>
Form partial (comments/form)
<%= form_for [#commentable, #comment] do |f| %>
<% if #comment.errors.any? %>
<div class="error_messages">
<h2>Please correct the following errors.</h2>
<ul>
<% #comment.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.text_area :content, rows: 8 %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Comments partial (comments/comments)
<div id="comments">
<% #comments.each do |comment| %>
<div class="comment">
<%= simple_format comment.content %>
</div>
<% end %>
</div>
Your error says undefined method each for nil:NilClass. As you can guess you are calling each on a nil object. Here your #comments is nil and hence giving your trouble.
In your view try something like this:
<div id="comments">
<% if #comments %>
<% #comments.each do |comment| %>
<div class="comment">
<%= simple_format comment.content %>
</div>
<% end %>
<% end %>
</div>
Edit:
So if you look at your code you have #comments till here:
<% if #comments.any? %>
<%= render "comments/comments" %>
<% else %>
#do stuff
<% end %>
it's after you call your partial that your #comment is lost so try this:
<% if #comments.any? %>
<%= render "comments/comments", comments: #comment %>
<% else %>
#do stuff
<% end %>
and then in your view use
<div id="comments">
<% comments.each do |comment| %>
<div class="comment">
<%= simple_format comment.content %>
</div>
<% end %>
</div>
Hi i need to print out just the candidates where active is == 0 here is my code in the view.
I can print if active is yes or no.. But in the each do loop i just want to print the active candidates.
So how can i add the condition to my each do loop, thanks.
<% #candidates.each do |candidate| %>
<div id="candidateper">
<div class="avatth" ><div class="avat_min">
<% if candidate.avatar.present? %>
<%= link_to (image_tag candidate.avatar.url(:thumb)), (candidate_path(candidate)) %>
<% else %>
<%= link_to (image_tag ("espanol/playersample.png")), (candidate_path(candidate)) %>
<% end %>
</div></div>
<div class="nameth"><%= candidate.name %></div>
<div class="activeth"><%= candidate.active ? t('generales.yess') : t('generales.noo') %></div>
<div class="generalth">
<% if candidate.user.purchased_at.present? %>
<%= candidate.user.purchase_defeated? ? t('generales.defeated') : t('generales.active') %>
<% else %>
<%= t('generales.noo') %>
<% end %>
</div>
<div class="actionsth"><%= link_to t('generales.show'), candidate_path(candidate) %>
<% if current_user.user_type == 'admin' %>
<%= link_to t('generales.delete'), candidate_path(candidate), method: :delete, data: { confirm: t('generales.delete_candidate_confirm') } %>
<% end %>
</div>
</div>
<% end %>
</div>
<% end %>
I`ve tried this
no luck syntax error on all my ideas :P
If candidate.active is actually a boolean then you could say:
<% #candidates.reject(&:active).each do |candidate| %>
...
<% end %>
If #candidates is actually an ActiveRecord::Relation then you could probably say:
<% #candidates.where(:active => false).each do |candidate| %>
...
<% end %>
to avoid pulling a bunch of stuff out of the database when you don't want it.
If active is actually a number (inside the database and outside the database) then you could say:
<% #candidates.select(&:zero?).each do |candidate| %>
...
<% end %>
or
<% #candidates.where(:active => 0).each do |candidate| %>
...
<% end %>
Menu has_many :dishes.
I want to sort the dishes by Dish.number.
Currently in my view it looks like:
<table class="menu">
<% #menu.dishes.each do |dish| %>
<div class="dish">
<tr>
<td>
<div class="dish_div dish_name">
<% if #menu.name != 'Övrigt' && #menu.name != 'Box to go' %>
<span class="dish_name"><%= "#{dish.number}. #{dish.name}" %></span>
<% else %>
<span class="dish_name"><%= "#{dish.name}" %></span>
<% end %>
<% if dish.strength_id == 2 %>
<%= image_tag('chili.png') %>
<% elsif dish.strength_id == 3 %>
<%= image_tag('chili.png') %>
<%= image_tag('chili.png') %>
<% elsif dish.strength_id == 4 %>
<%= image_tag('chili.png') %>
<%= image_tag('chili.png') %>
<%= image_tag('chili.png') %>
<% end %>
</div>
<div class="dish_div"><%= "#{dish.description}" %></div>
<div class="dish_div dish_price"><%= "#{dish.price} kr" %></div>
</td>
</tr>
</div>
<% end %>
</table>
How do I do that?
Should it be in the view or controller?
Thanks
Neither! :) --- do it in your model definitions
If you always want to order on strength:
class Menu
has_many :dishes, :order=>'strength_id DESC'
end
class Dish
belongs_to :menu
end
Otherwise, just order in the view:
<% #menu.dishes.sort_by{|dish| dish.strength_id}.each do |dish| %>
In your controller:
def list
#dishes = #menu.dishes.all(:order => :number)
end
In your view:
<% #dishes.each do |dish| %>
I'm not sure if I understood what you're trying to do, but … to iterate the dishes sorted by their number attribute, you just need to use the :order option on the dishes:
<% #menu.dishes.all(:order => :number).each do |dish| %>
...
<% end %>
You can use the order method:
<% #menu.dishes.order(number: :asc).each do |dish| %>