I have three models: posts, questions and comments (comments belong to questions and questions belong to posts) and am trying to show the last 2 questions on the comments index page.
Here is my comments_index function:
def index
#question = Question.find params[:question_id]
#comments = #question.comments
#questions = #comment.questions.order(:created_at).limit(2).reverse_order
end
and my comments_index:
<% #questions.each do |question| %>
<%= question.body %>
<% end %>
Here is the error i am getting:
undefined method `questions' for nil:NilClass
My routes.rb file looks like this:
resources :posts do
resources :questions do
end
end
resources :questions do
resources :comments do
end
end
Question has_many comments?
Comment belongs_to question?
If that's the case, you will only be able to get the comment's 1 question... but you're already getting that when you go to the question page... If you're just trying to get the last 2 questions asked (period), you can do:
#post = #question.post
#questions = #post.questions.order(:created_at).last(2)
That will get you the last 2 questions in the database.
and your routes... shouldn't it be:
resources :posts do
resources :questions do
resources :comments do
end
end
end
?
There is a typo. you are initializing #comments but using #comment
def index
#question = Question.find params[:question_id]
#comments = #question.comments
#questions = #comments.collect{|c|c.questions.order(:created_at).limit(2).reverse_order}
end
Since comments is a collection, you would want to get the last 2 questions from each comment
Related
I have an app where users can ask questions and bookmark certain questions. I'm done with the users, questions, and answers, so I've added a BookmarkController & Bookmarks model. At first, I considered using associations, but my app has a few associations already so I'm (or I've attempted at) using query parameters such as user_id and question_id to fetch bookmarks.
The structure is a bit like StackOverflow. A user navigates to a single question view and bookmarks it on that page. This creates a new bookmark model containing the user_id of current_user and the question_id. The user can go to his profile to view all the questions he bookmarked, fetched using his user_id. (Answers cannot be bookmarked. Only questions.)
I've been getting a 'param is missing or the value is empty: bookmark' error, although I have followed similar steps I did for my QuestionsController. It would be great if someone could help me out in identifying what's wrong/bad about my code!
rake routes (first part omitted)
bookmark_question PUT /questions/:id/bookmark(.:format) questions#bookmark
questions GET /questions(.:format) questions#index
POST /questions(.:format) questions#create
new_question GET /questions/new(.:format) questions#new
edit_question GET /questions/:id/edit(.:format) questions#edit
question GET /questions/:id(.:format) questions#show
PATCH /questions/:id(.:format) questions#update
PUT /questions/:id(.:format) questions#update
DELETE /questions/:id(.:format) questions#destroy
route.rb (excerpt)
# Questions
get '/questions/:id' => 'bookmarks#create'
show.html.erb (questions#show)
<% if current_user %>
<%= link_to "Bookmark", :controller => 'bookmarks', :action => 'create' %>
<% end %>
BookmarksController
class BookmarksController < ApplicationController
def new
#bookmark = Bookmark.new
end
def create
#question = Question.find(params[:id]) # when I delete this line, I get a new error - "undefined local variable 'params'"
#bookmark = Bookmark.new(bookmark_params)
#bookmark.user_id = current_user.id
#bookmark.question_id = #question.id
#bookmark.save
redirect_to #question
end
def destroy
end
private
def bookmark_params
params.require(:bookmark).permit(:user_id, :question_id)
end
end
Bookmark model
class Bookmark < ApplicationRecord
validates :user_id, presence: true
validates :question_id, presence: true
end
QuestionsController
(at the moment, contains no reference to Bookmarks. I thought so because I did the routing, but this might be where I'm going wrong)
class QuestionsController < ApplicationController
def index
#questions = Question.all
end
def show
#question = Question.find(params[:id])
#answers = Answer.all
# Delete only appears when no answers
#deletable = (current_user== User.find(#question.user_id)) && (#question.answers.all.size==0)
end
def new
#question = Question.new
end
def create
if logged_in?
#question = Question.new(question_params)
#question.user_id = current_user.id
#question.save
redirect_to #question
else
redirect_to login_path
end
end
def destroy
#question = Question.find(params[:id])
#question.destroy
redirect_to root_path
end
private
def question_params
params.require(:question).permit(:picture_url, :country, :educational_level, :topic)
end
end
profile index.html.erb (just for ref)
<% if (#bookmarks.count == 0) %>
///
<% else %>
<%= #bookmarks.each do |bookmark| %>
<!-- Show bookmark content here like Question.find(bookmark.question_id) etc -->
<% end %>
<% end %>
I have looked a the previous qns that have the same error as me. But they were all using associations. I hope to not use associations as the bookmark model only needs to keep a record of the user id and qn id.
UPDATE
So, referring to the answers given, I updated my erb to:
<% if logged_in? %>
<%= link_to "Bookmark", :controller => 'bookmarks', :action => 'create', bookmark: {user_id: current_user.id, question_id: #question.id} %>
<% end %>
hence specifying the controller and action (and the params) that need to be directed. But rails sends an error:
No route matches {:action=>"create", :bookmark=>{:user_id=>2, :question_id=>4}, :controller=>"bookmarks", :id=>"4"}
So I assume it was a routing problem. As Pavan suggested, I did consider nesting my resources, but the nesting is already one level deep, as such:
resources :questions do
resources :answers
end
And I reckon doing something like:
resources :questions do
resources :bookmarks # or resources :bookmarks, only: create
resources :answers
end
won't work. (And it didn't :( )
I'm not so sure how to get this routing problem fixed (tried Googling). Thanks.
param is missing or the value is empty: bookmark
The reason for the error is bookmark_params expects a :bookmark key to be present in the params hash, which in your case is missing since you are not passing any.
Change link_to like below:
<% if current_user %>
<%= link_to "Bookmark", :controller => 'bookmarks', :action => 'create', bookmark: {user_id: current_user.id, question_id: #question.id} %>
<% end %>
Also, the route get '/questions/:id' => 'bookmarks#create' isn't right and would conflict with this route question GET /questions/:id(.:format) questions#show. I would instead recommend building nested routes
resources :users do
resources :questions do
resources :bookmarks, only: [:create]
end
end
Update:
Along with the above, you should change #question = Question.find(params[:id]) to #question = Question.find(params[:bookmark][:question_id])
'param is missing or the value is empty: bookmark, this error means that, there is no bookmark key present in your params object, but you defined your bookmark_params to have one:
def bookmark_params
params.require(:bookmark).permit(:user_id, :question_id)
end
That's why it's throwing the above error message.
You should make sure you send the user_id and question_id key/value pairs under the bookmark key. Something like this:
bookmark: { user_id: 1, question_id: 2}.
So, your code should look something like this (adding the bookmark to params):
<%= link_to "Bookmark", :controller => 'bookmarks', :action => 'create', bookmark: {user_id: current_user.id, question_id: #question.id} %>
I've made a comments section for my 'posts' views and I've got remote: true working on the form so when you hit enter and submit the 'new comment' form to the database, it updates in the background fine (the comment is created, page doesn't redirect or change) but I can't get it to load the comments on the page. You have to refresh the page to see them.
I could do redirect_to :back in the comments controller after saving but that takes user to top of the page rather than staying put to see the comment appear.
I've tried render 'posts#show' after saving the comment in the comment controller create action but that tries to send you to /comments/posts/:slug/. If it actually rendered the posts show action I think this would work.
Comments controller:
class CommentsController < ApplicationController
before_action :find_commentable
def show
end
def new
#comment = Comment.new
end
def create
#comment = #commentable.comments.new comment_params
#comment.author = current_user if current_user
#comment.save
end
private
def comment_params
params.require(:comment).permit(:body, :author_id, :post_id)
end
def find_commentable
#commentable = Comment.find(params[:comment_id]) if params[:comment_id]
#commentable = Post.find_by_slug(params[:post_id]) if params[:post_id]
end
end
Comment section on post show view:
%ul#post-comments
= render 'comment_feed'
= form_for [#post, Comment.new], remote: true do |f|
= f.text_field :body, class: 'js-new-comment-field', placeholder: "Write a comment..."
posts/show.js.erb:
$("#post-comments").html("<%= escape_javascript render("comment_feed") %>");
Routes.rb:
resources :posts do
collection do
match 'search' => 'posts#search', via: [:get, :post], as: :search # For ransack search
end
resources :comments
end
resources :comments do
resources :comments # Replies on comments
end
Got it working!
This helped loads:
https://gemfile.wordpress.com/2014/03/06/rails-blog-comments-with-ajax/
I added this second match line to routes.rb and it's refreshing the page with the new comment now:
resources :posts do
collection do
match 'search' => 'posts#search', via: [:get, :post], as: :search
match '/comments/posts/:slug' => 'posts#show', via: [:get, :post], as: :comment
end
resources :comments
end
It's not ajax though: demo
My app is a web forum. Root page is a list of user-submitted
categories. I click one and it links to a list of user-submitted posts
about that category. I click a post and it links to a list of comments
about that post. Those are the 3 tiers.
CATEGORIES INDEX This is a list of clickable categories
<% #categories.each do |category| %>
<%= link_to category.title, category %>
<% end %>
CATEGORIES SHOW I clicked a category, now I'm here looking at a list of posts
<%= render :partial => #category.posts %>
<% end %>
_POSTS The posts are rendered from this here partial
<%= div_for(post) do %>
<%= link_to post.body, Post %>
Clicking that post link takes me to POSTS INDEX.
I'm not sure if this is a desirable flow of a Rails app. It seems odd
to go from Categories, to Posts, to Comments using Categories_Index,
Categories_Show, and Posts_Index, respectively. I don't know how to display or submit comments from this POSTS INDEX. #comments.each do |comments| provides an error and so does the render: partial method. I can not use the same methods for Comments that I used for Categories and Posts.
MODELS Models are complete with has_many, belongs_to, etc.
CATEGORIES CONTROLLER
def index
#categories = Category.all
end
def create
#category = current_user.categories.build(categories_params)
end
POSTS CONTROLLER
def create
#category = Category.find(params[:category_id])
#post = #category.posts.new(post_params)
COMMENTS CONTROLLER
def index
#subcomments = Subcomment.all
end
def create
#subcomment = current_user.subcomments.build(subcomment_params)
end
ROUTES
Rails.application.routes.draw do
resources :comments
resources :posts
devise_for :users
resources :categories do
resources :posts do
end
resources :comments
end
root "categories#index"
I successfully added posts to categories. How can I add comments to posts? Is my approach correct?
I assumed you have the following Model Relationships:
Model Category
has_many :posts
Model Post
has_many :comments
belongs_to :category
Model Comment
belongs_to :post
You are asking "How can I add comments to posts?"
In the page where you render all POSTS data,
you should USE posts ID as you main parameter.
So, meaning you should have post_id column/field inside Comments Table.
After saving the comments data, usually like [title, message, date ....].
In your Post Controller, you can get comments like:
// multiple Posts data
#posts = Post.all
#post.each do |post|
post.comments
...
end
//single Post
#post = Post.first // or Post.find(:id => params[:post_id])
#post.comments
If you are sending data using form, just put some hidden text field,
setting the name & value:
name="post_id"
// or something like:
name="comment[:post_id]"
//depends on how you constract the form.
Then set the value:
value="<%= params[:post_id ]%>"
Finnally, you can get the value like getting the other comments_field names.
Usually you should have this in in config/routes.rb,
resources :commets
Then your FORM path is like:
<%= form_for #comment, :url => #comments_path %>
Your Comments Controller should have like:
def index
...
end
def show
...
end
def edit
...
end
def new
#comment = Comment.new
end
def create
#comment = Comment.create(comment_params)
if #comment.save
....
redirect_to comments_path
else
.....
end
end
# For params permit in Rails 4 ^
def comment_params
params.require(:comment).permit!
end
How can we list out the user's name who submitted the habit: <%= link_to #habit.user.name, #user %>, but upon clicking on it the user is redirected back to the show page: http://0.0.0.0:3000/habits/1 instead of being redirected to the user's profile page: http://0.0.0.0:3000/users/1?
habits_controller
def show
#notable = #habit
#notes = #notable.notes
#note = Note.new
#commentable = #habit
#comments = #commentable.comments
#comment = Comment.new
#correct_user = current_user.habits.find_by(id: params[:id])
end
routes.rb
resources :users do
resources :habits
end
resources :habits do
resources :notes
resources :notifications
resources :comments do
resources :likes
end
member do
post :like
post :notifications
end
resources :levels do
# we'll use this route to increment and decrement the missed days
resources :days_missed, only: [:create, :destroy]
end
end
When you pass #user as the second parameter of the link_to method call, Rails is inferring the user_path route. Instead of #user, you should be able to pass #habit and see the appropriate behavior.
If the implicit path argument doesn't work, you could more specifically pass habit_path(#habit.id)
Have you tried to change the link url to be more specific?
I.e. <%= link_to #habit.user.name, user_path(#habit.user) %>
I guess your #user instance is not defined correctly. What you defined as #user is actually habit instance.
Using this post as guidance I am trying to create a link to the next comment on my comments show page. I am getting this error however:
undefined method `next' for #<Comment:0x00000103d59db0>
In my routes comments belong to posts:
resources :posts do
resources :comments
end
In my posts model I have this:
def next
post.comments.where("id > ?", id).order("id ASC").first
end
My comments controller:
#post = Post.find(params[:post_id])
#comment = Comment.find params[:id]
#commentnext = #post.comments.find(params[:id])
and then in my comments show view I have the link:
<%= link_to "Next Comment", post_comment_path(#post, #commentnext.next) %>
From the Source you attached,I guess you put the method in wrong model.It should be in Comment model
Try putting this in the Comment model instead of Post model
#comment.rb
def next
post.comments.where("id > ?", id).order("id ASC").first
end