Have a show action on a ticket that pulls in a list of comments on the ticket. My goal is to display the list of ticket comments and then above it give the option for someone to add a comments.
This works when the form is below the list of comments, however when i put the above the comments, i get an error in the render of the comments saying that the record has no user id. Almost like the #comments in my ticket controller is somehow getting this new thing added from the form even though it is instantiated before the render of the form.
Here are my partials and controller. The error when the form is displayed first is "unable to find user_id = 0" That is due to the comments.commenter, which looks for the name of the person submitting the comment.
Ticket Controller
def show
#ticket = Ticket.find(params[:id])
#comments = #ticket.comments
end
tickets/show - The form is in here twice, but i only put it in once when trying to get this to work. I want it to work in the top spot.
<div class="widget-content nopadding">
<ul class="new-comment">
<%= render "comments/form" %> --- Does not work here
</ul>
<ul class="recent-comments">
<%= render #comments %>
</ul>
</div>
<%= render "comments/form" %> --- Works here,
comments/form
<%= form_for([#ticket, #ticket.comments.build]) do |f| %>
<div class="field">
<%= f.label :content %><br>
<%= f.text_area :content %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
comments/comment
<li>
<div class="comments">
<span class="user-info"> User: <%= comment.commenter %> </span>
<p>
<strong>Comment:</strong>
PUBLIC: <%= comment.try(:content) %>
</p>
</div>
</li>
Do you have a default set on the comment user_id to 0? What's happening is the form is building a new comment on the ticket. So i think that is getting rendered in the collection partial in addition to what the ticket already had. With the user_id set to zero, the comment.commenter tries to do the where id = 0, and it blows up.
So if you do have a default on that column, remove it. Foreign keys should default to nil.
The #comments is likely lazy loaded, that's why the _comment partial can be effected. #comments was not invoked until you have the second render. To avoid this, you can switch the #comments in the controller to:
#comments = Comment.where(ticket_id: params[:id])
Hope this made sense. Let me know if the default is the case. It's just a hunch :)
Related
Rails each do method is acting strangely and I do not know why.
controller
def index
#fabric_guides = FabricGuide.with_attached_image.all.order(:name)
end
index.html.erb
<div class="guide-items">
<%= #fabric_guides.each do |fabric| %>
<div class="guide-container">
<%= link_to fabric_guide_path(slug: fabric.slug) do %>
<%= image_tag fabric.image if fabric.image.attached? %>
<% end %>
<div class="guide-info">
<p class="g-name">
<%= link_to fabric.name,
fabric_guide_path(slug: fabric.slug) %>
</p>
</div>
</div>
<% end %>
</div>
I have two FabricGuide records so I expect two "guide-container" but I get three. Or more precisely I get two guide containers and a third block of text containing all the content from the last FabricGuide record.
I have almost an identical setup for articles and have never encountered this problem. I'd happily share more information if needed. Thank you!
Please remove = equal sign from your each loop of view code
like below :-
<% #fabric_guides.each do |fabric| %>
...
...
<% end %>
you have used this <%= #fabric_guides.each do |fabric| %> in your view that's why it shows all record in DOM.
The expression for erb tags is <% %>
now if we want to print that tag too then we apply <%= %>
I'm building a basic forum application in Ruby on Rails (v4.1.7) and I'm having an issue with displaying the topics in descending order based on their last post. The code I'm using below will show the topics in the correct descending order, however the last post times and last poster name are wrong.
When I view the topic with comments#index, these data are correct. Both comments#index and topics#index call the same partial to display the topic:
I believe this may have to do with me calling topic.comments.last
Testing it out, it seems to be displaying the FIRST comments userdata and created_at, rather than the last, however the forums ARE showing up in the correct order.
Partial: _topic.html.erb:
<article class="topic">
<h2><%= link_to(topic.title, topic_comments_path(topic)) %></h2>
<div class="author">
By <strong><%= topic.user.name %> </strong>
on <%= topic.created_at.strftime('%b %d %Y') %>
</div>
<div class="stats">
Viewed <%= pluralize(topic.view_count, 'time') %>.
<% if topic.comments.any? %>
Last comment <%= time_ago_in_words(topic.comments.last.created_at) %> ago
by <%= topic.comments.last.user.name %>.
<% else %>
No comments.
<% end %>
<span class="pull-right">
<%= pluralize(topic.comments.count, 'comment') %>.
</span>
</div>
</article>
topics_controller#index (produces incorrect data):
def index
#topics = Topic.includes(:comments).order('comments.created_at desc')
end
I have also attempted:
def index
#topics = Topic.includes(:comments).paginate(page: params[:page]).order('comments.created_at desc')
end
topics/index.html.erb(wrong data):
<% provide(:title, 'Forum Index') %>
<%= render partial: #topics, spacer_template: 'shared/hr' %>
Viewing a specific thread (in this case the topic.comments.last.user.name and topic.comments.last.created_at are the correct values):
def index
#context = context
#comments = #context.comments.paginate(page: params[:page])
end
#...
private
def context
Topic.find(params[:topic_id]) if params[:topic_id]
end
topics/index.html.erb (right data):
<% provide(:title, #context.title) %>
<h1>View Discussion</h1>
<%= render(partial: 'topics/topic', object: #context) %> # Partial with right data
<hr />
<%= render(partial: 'comment',
collection: #comments,
spacer_template: 'shared/hr',
locals: { topic: #context }) || 'No comments.' %>
<hr />
<%= render partial: 'comment_form', locals: { context: #context,
comment: #context.comments.new } %>
topic.comments.last
should be
topic.comments.first
because you're placing the latest comments first.
Where it's working fine, it is because you aren't ordering the comments and the last will fetch the comment with the highest primary index value which is most likely the ID.
Hope that clears it up.
And just FYI:
topic.comments.count
will fire up another query in your view. Change the count to size
There are posts, comments & users. I want to post number of comments for a specific user in comments list on Post show page. I know I need to define #user, but I don't know how to define it, so that it shows specific number for every user. User is author of the comment.
Post controller
def show
#post = Post.find(params[:id])
#comment = Comment.new
#comments = Post.find(params[:id]).comments.order(created_at: :desc)
#user = ???
end
Post /show action - error is for - #user.comments.count
<div class="row">
<% #comments.each do |comment| %><br>
<div class="col-sm-4"> <%= link_to comment.user.name, user_path(comment.user) %> <br>
<%= image_tag(comment.user.smallimage) %><%= #user.comments.count %>
</div>
<div class="col-sm-8"> <b><%= comment.title %>:</b>
<div>
<% if comment.content.length > 250 %>
<%= truncate(comment.content, length: 250) %>
<%= link_to_function '...Read more', "$(this).parent().html('#{escape_javascript comment.content}')" %>
<% else %>
<%= comment.content %>
<% end %>
</div>
</div>
<% end %>
</div>
If you define an #user you will only have one user or a group of users that doesn't relate to your comments. You don't need it. You can just use the relationship between user and comment like this:
<%= comment.user.comments.count %>
Note that this will run a database query for each comment to get the total comment count for that user. For performance reasons you may want to use a counter cache for this instead.
If you defined the association in the post model belongs_to :user then you can probably do #user = #comment.user
But, if that's the case then you can call that from the view with #comment.user.name or something like that.
I'd like to see the whole codebase if you've pushed to GitHub.
My current setup is that a discussion has many posts. Thus, the show action of discussions shows a list of posts.
discussions/show.html.erb:
<% for post in #discussion.posts %>
<div class="post" id="<%= post.id %>">
<div class="post-content">
<div class="post-user">
<div class="name"><%= link_to post.user.username, post.user %></div>
</div>
<div class="post-body">
<%= post.content %>
</div>
</div>
</div>
<% end %>
And this is my discussions_controller show action:
def show
#forum = Forum.find_by_permalink(params[:forum_id])
#discussion = Discussion.find(params[:id])
end
Every time I attempt to add the paginate method to my view, I get a series of errors. I know I'm stepping on the wrong foot here, so where should I start to be able to get paginate working for this page?
Many thanks in advance, still somewhat new to Rails!
change
#discussion = Discussion.find(params[:id])
to
#posts = Discussion.find(params[:id]).posts.page(params[:page]).per(20)
Your view would then be
<% for post in #posts %>
Then you'd add the paginate code in the view
<%= paginate(#posts) %>
While trying to build a form to create new items on an index page rather than the new view, i ran into a curious problem.
When presenting the form for creation of a new task in the current project, the #tasks variable that contains the tasks that are supposed to be displayed in the list below, seems to be empty. Therefore i get a "No route matches" since the object im passing to ie. complete_project_task_path is nil.
When removing the form, everything works like a charm. Any ideas why this happens?
<h1>Listing tasks</h1>
<%= form_for([#project, #project.tasks.build]) do |f| %>
<div id="new_quick_task">
<%= f.text_field :title, :value => 'Quickly add a new task' %>
<%= f.submit %>
</div>
<% end %>
<div id="task_list">
<% #tasks.each do |task| %>
<div class="task">
<div class="completed"><%= task.completed %></div>
<div class="complete_link"><%= link_to "Good", complete_project_task_path(#project, task) %></div>
<div class="title"><%= link_to task.title, project_task_path(#project, task) %></div>
</div>
<% end %>
</div> <!-- end task_list -->
Why do you use #tasks and not #project.tasks? because it would show the new task you created for your form?.
Well, you could still use #project.tasks and do something like:
<% #project.tasks.each do |task| %>
<% unless task.title.nil? %>
<div class="task">
<div class="completed"><%= task.completed %></div>
<div class="complete_link"><%= link_to "Good", complete_project_task_path(#project, task) %></div>
<div class="title"><%= link_to task.title, project_task_path(#project, task) %></div>
</div>
<% end %>
<% end %>
which would skip the tasks without the title.
The error you get is not because the #tasks variable is empty, because if it was, you would never come to the code below it. The error you get is that one of the items inside your #tasks contains a value it does not expect. I guess it has something to do with your complete_project_task_path(#project, task) that will check something of task that is not set correctly?
So i think i figured it out. (please correct me if im wrong)
Ruby variables hold references to
objects and the = operator copies the
references.
(from http://ruby-doc.org/docs/Newcomers/ruby.html#objects no. 17)
Taking that into account, look at the following example
#task_list = #project.tasks
This essentially makes #task_list refer to the same object as #project.tasks. If the data in #project.tasks changes, so does #task_list's data because they both point to the same object.
#project.tasks.build seems to alter the object, that both #project.taks and #task_list point to, in some way.
The solution was pretty simple. Instead of setting #task_list = #project.tasks i created a new object for #task_list.
So in the controller, istead of doing this:
#project = Project.find(params[:project_id])
#task_list = #project.tasks
just do it like this:
#project = Project.find(params[:project_id])
#taks_list = Task.where(:project_id => #project.id)