Undefined method with link to next comment - ruby-on-rails

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

Related

ROR5: 'param is missing or the value is empty' error with adding Bookmarks

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} %>

How to call a method from controller using link_to?

I want my app to add a book to current_user when he clicks the link. My code seems to be ok, there are no errors but after user clicks the link nothing happens.
book.rb:
has_many :book_users
has_many :users, through: :book_users
user.rb:
has_many :book_users
has_many :books, through: :book_users
book_user.rb:
belongs_to :book
belongs_to :user
books_controller.rb:
before_action :is_admin?, except: [:book_params, :add_to_books_i_read, :index]
before_filter :authenticate_user!
expose(:book, attributes: :book_params)
expose(:books)
def create
if book.save
redirect_to(book)
else
render :new
end
end
def update
if book.save
redirect_to(book)
else
render :edit
end
end
def add_to_books_i_read(book_id)
current_user.books << Book.find(book_id)
end
In my index view I have
ul
-books.each do |book|
li
= link_to "#{book.name}", book_path(book)
= link_to " Add to my books", {:controller => "books", method: :add_to_books_i_read, book_id: :book.id}
So, what am I doing wrong? Why my method add_to_books_i_read does nothing? The table in database book_users doesn't record anything after clicking this link_to, but it works well itself (I checked via console). What can I do? How to make users add books through the method and how to call this method correctly? Every help would be appreciated, thank you!
= link_to " Add to my books", {:controller => "books", action: :add_to_books_i_read, book_id: :book.id}
The first, method in the link_to is the symbol of HTTP verb so you can not pass your function in the controller
To define and use new action on you controller you need to define route for that see here
Also try to organize your routes as (note member section)
resources :books do
member do
get :add_to_books_i_read
end
end
and see Prefix Verb column in rake routes output.
From #Ioannis Tziligkakis, I edited a bit.
Try:
# config/routes.rb
resources :books do
member do
get :add_to_books_i_read
end
end
# app/controller/books_controller.rb
def add_to_books_i_read
current_user.books << Book.find(params[:id])
# redirect or other logic
end
# app/views/books/index.html.haml
ul
- books.each do |book|
li
= link_to "#{book.name}", book_path(book)
= link_to "Add to my books", add_to_books_i_read_book_path(book.id)
Try this:
# config/routes.rb
resources :books do
# just not about method:
# use get for request, search
# use put for update
# use post for create
# use delete for destroy
put :add_to_books_i_read, on: :member
end
# app/controller/books_controller.rb
def add_to_books_i_read
#book = Book.find(params[:id])
current_user.books << #book
respond_to do |format|
format.js
end
end
# app/views/books/index.html.haml
ul
- books.each do |book|
li{:id => "book_#{book.id}"}
= render "links", book: book
# add field: app/views/books/_links.html.haml
= link_to "#{book.name}", book_path(book)
= link_to "Add to my books", add_to_books_i_read_book_path(book), method: :put, remote: true
# add field: app/views/books/add_to_books_i_read.js.erb
$("#book_<%= #book.id %>").html("<%= j render 'books/links', book: #book %>")
Since add_to_books_i_read is a controller action method you should update your routes to include this action for books resources in order to play nicely with Rails way of doing thing in a resourceful way. You also get to use a URL helper for this path that will look like this:
/books/:id/add_to_books_i_read
Your code could look like this:
# config/routes.rb
resources :books do
get :add_to_books_i_read, on: :member
end
# app/controller/books_controller.rb
def add_to_books_i_read
current_user.books << Book.find(params[:id])
# redirect or other logic
end
# app/views/books/index.html.haml
ul
- books.each do |book|
li
= link_to "#{book.name}", book_path(book)
= link_to "Add to my books", add_to_books_i_read_book_path(book)
Oh God. With your advise help I've finally got it! So,
Controller:
def add_to_books_i_read
current_user.books << Book.find(params[:id])
redirect_to(:back) #this line
end
In routes
resources :books do
member do
get :add_to_books_i_read
end
end
index view
-books.each do |book|
li
= link_to "#{book.name}", book_path(book)
= link_to " Add to my books", add_to_books_i_read_book_path(book)
Thank you all for your help! I'm really really grateful! :)

Ruby on Rails 3 Tiered Link Program

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

Undefined method 'questions'

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

How to redirect from a child class to the parent class#show view?

I have an application where an Event has_many Videos, which belongs_to an Event. How can I click on an instance of the video and have it redirect to the events#show view using it's event_id foreign key to identify the correct event? The association definitely works, but I'm struggling to think through the logic, or even where the redirect should take place i.e. in the routes, the controller or the view?
Here's some code which may be relevant:
From the view
<% #video.each do |v| %>
<li><%= link_to image_tag(v.video_thumb('150'), width: 150), v %></li>
<% end %>
class VideosController < ApplicationController
def show
#video = Video.find(params[:id])
if current_event
#videos = current_event.videos
#random_video = current_event.videos.random
else
#videos = Video.all
#random_video = Video.random
end
end
class EventsController < ApplicationController
def show
#event = Event.find_by_name(request.subdomain)
if request.params[:id].present?
#event = Event.find(params[:id])
end
if not #event.nil? and #event.videos.any?
#video = Video.random(#event)
#comment = #video.comments.new
#comments = #video.comments
end
end
resources :events do
match '', to: 'events#show', constraints: lambda { |r| r.subdomain.present? && r.subdomain != 'www' }
end
resources :videos
Let me know if there is any other code you might need to help and I will update the question with the relevant code.
Thanks for any help....
You can use event_path(#event.video)
Let me tell you that, when a video belongs to event, you can easily find the association event related to that video will be easily found from that object. For example:
#video = Video.find(params[:id])
#event = #video.event
for link generation simply: link_to #event.name, event_path(#event)
// if there is any subdomain for that event and if subdomain define the
EventsController#show as root then to go to that event show page we can write:
link_to "#{#video.event.name}", root_url(:subdomain =>
#video.event.name)
or same:
link_to "#{#event.name}", root_url(:subdomain => #event.name
I hope this will work!

Resources