Rails has_many error - Couldn't find ID - ruby-on-rails

I have a Comment and Reply.
comment has_many replies
routes.rb
resources :comments do
resources :replies
end
When I open comments/index and then select comments/show I print information about all the replies that are related to that comment.
<% #comment.replies.each do |reply| %>
I can also create another reply. All this works properly.
The problem comes when I decide to edit one of those replies.
<%= link_to 'Edit', edit_comment_reply_path(#comment.replies,reply) %>
The strange thing is that if there is a comment with an ID the same as the ID of the reply that I want to modify, the edit is working properly. It is not even necessary the particular reply that I want to modify to belongs to that comment. But in case I want to edit reply with ID for example 66, but there is not a comment with id 66, I get an error:
Couldn't find Comment with 'id'=65
<%=form_with(model: #reply, url: [Comment.find(params[:id]), #reply]) do |form| %>
This is replies/_form.html.erb which apparently works as an edit form as well. In this case the reply.id is 65 and it is looking for a comment with the same ID which is not present.

Did you try?
<%= link_to 'Edit', edit_comment_reply_path(reply) %>

What do your controllers look like? Also, you shouldn't be able to access replies that do not belong to your comment. Look at using proper scoping and authorization. I would guess the only reason it works is luck; because you do have a comment_id that matches the reply_id, the call does not fail.

Ok, can you also post your comments controller.
A few points:
Make use of authorizations in your relevant functions (suggestion; assuming you're using policies)
def edit
authorize #reply
end
If you plan on passing in the comment id, you should also set_comment (not just in create). That way you can also make sure the reply edit is not executed using a comment that does not belong to your user (or some other unwanted behaviours).
And also, you question talks about looking for Id 66, but the error mentions ID 65. Is that just a typo?

In your RepliesController change the set comment method to
def set_comment
#comment = Comment.find(reply_params[:comment_id])
end

The problem lies in this line of code.
<%= link_to 'Edit', edit_comment_reply_path(#comment.replies,reply) %>
The edit_comment_reply_path method takes #comment as its first argument.
The correct code should be
<%= link_to 'Edit', edit_comment_reply_path(#comment, reply) %>
Provided that you have assigned #comment in your controller edit action.
def edit
#comment = Comment.find(params[:comment_id])
end
Or
before_action :set_comment, only: [:create, :edit]
The point is you must set the #comment in the correct action for the view.
The form_for is incorrect. You can passing in params[:id] which is the id of #reply.
<%= form_with(model: #reply, url: comment_reply_path(#comment, #reply)) do |form| %>

Related

How to change a column attribute with a link/button - Ruby on Rails

I am learning RoR and I'm currently trying to have an up-vote system implemented into my website. Users can log on and post comments on a forum and then upvote other comments on that forum.
Controller code
def upvote
#comment = Comment.find(params[:comment])
#comment.update_attribute('upVote', #comment.upvote + 1)
redirect_to :back
end
Link in show
<%= link_to 'Up Vote', comment_upvote_path(comment.id), method: :put %>
I tried substituting (comment.id) with comment to no avail.
Routes
get 'upvote', :to=>'comments#upvote'
resources :comments do
put :upvote
end
The error that I'm getting happens when I click to upvote:
Couldn't find Comment with 'id'=
app/controllers/comments_controller.rb:26:in `upvote'
Request
Parameters:
{"_method"=>"put",
"authenticity_token"=>"HNXyufzGsXi/SZoJsa+2uouMKVYlH6vYTHOF8iMgj6zAHO13jApk+QO33xEonkcoFgMugwYQZpSom1+KbVRe7g==",
"comment_id"=>"11"}
I checked and a comment with the id of 11 exists, so I really do not know what is causing this error. Any help would be very much appreciated!
By the looks of things, :comment should be :comment_id like so.
#comment = Comment.find(params[:comment_id])
put :upvote
Should be
put :upvote, on: :member

Search box to find user in rails

I'm somewhat new to rails. I'm going through making the classic twitter clone right now. I want to have a search bar on my homepage that allows the user to search for a twitter handle, and if the handle exists, it will send the user to the show page for that twitter handle.
I've been following a RailsCast on how to implement a simple search, but instead of doing it on the index like the video, I want to do it on the show action. I've run into some problems though. The form sits on my user index view.
Here is the error:
ActionController::UrlGenerationError in Users#index
Showing c:/Sites/Projects/twitterapp/twitter/app/views/users/index.html.erb where line #2 raised:
No route matches {:action=>"show", :controller=>"users"} missing required keys: [:id]
Here is the form:
<%= form_tag(user_path, method: 'get') do %>
<%= text_field_tag(:search, params[:search]) %>
<%= submit_tag("Search", name: nil) %>
<% end %>
Here is my show action:
def show
#user = User.search(params[:search])
end
And here is my search method in my user model:
def self.search(search)
if search
find(:all, conditions:['name LIKE ?', "%#{search}%"])
else
find(:all)
end
end
Actually you cannot use the show method as a search result finder. Because according to the rails convention:
For any resource like users, rails scaffold generates index,new, show, create, update, delete methods based on your routes files.
Thus based on the conventional way, show method always asks for an object. Lets say you are using UserContoller show method. It asks for a user object. Which you haven't provide in the form. that's why :id missing error is given.
I would tell you to do some more learning. And for searching create a different method in a different controller and define that controller method to the routes.rb file. This is the best way to do.
If you still want to use the show method, then change the show methods routing from the routes.rb file. You've to manually declare the show action on routes file.
you are using user_path and path need to inform id from present user
you can do this in action :index but I recommend you to create a action to this
view
<%= form_tag(search_users_path, method: 'get') do %>
<%= text_field_tag(:search, params[:search]) %>
<%= submit_tag("Search", name: nil) %>
<% end %>
routes.rb
resources :users do
post 'search', :on => :collection
end
users_controller.rb
def search
#user = User.search(params[:search])
end
You should to create a view search.html.erb similar as index.html.erb
As Emu and Breno pointed what causing the problem user_path requires an user id
Solution idea:
Why not just point to users index action? like this:
<%= form_tag(users_path, method: 'get') do %>
<%= text_field_tag(:search, params[:search]) %>
<%= submit_tag("Search", name: nil) %>
<% end %>
users_controller.rb:
def index
if params[:search]
#user = User.search(params[:search])
end
end
and you can use ajax remote: true to handle the returned user object
Found your question via Google, but the responses and suggestions didn't work for me. Found another solution that did, so seems worth posting here.
"Search and Filter Rails Models Without Bloating Your Controller":
http://www.justinweiss.com/articles/search-and-filter-rails-models-without-bloating-your-controller/

Rails App - Object_ID Returning for User Name

I am developing a simple blog app and am having trouble displaying the user name associated with a comment.
Comments belongs_to :posts and :users. Posts belongs_to :user and has_many :comments. Users has_many :posts and :comments.
The create action in my comments model works and stores the comments as expected with the post_id and user_id:
class CommentsController < ApplicationController
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.create(comment_params)
#comment.user = current_user
if #comment.save
redirect_to #post
else
flash.now[:danger] = "error"
end
end
private
def comment_params
params.require(:comment).permit(:content)
end
end
I am able to access the user name via the console as expected with Comment.first.user.name which returns the users name. When trying to do this in the view, I get the following error:
undefined method `name' for nil:NilClass
Here is the view:
<% #post.comments.each do |comment| %>
<p>User:<%= comment.user.name %></p>
<p>Comment:<%= comment.content %></p>
<% end %>
When I remove the .name from the user in the view, the app displays what looks to be the object_id.
User:#<User:0x00000001f62830>
Comment:Test comment
I've tried resetting the database mentioned here: Show username when posting comments in Rails
I've also tried to address the proxy_id mentioned here: Returning issue in Comment::ActiveRecord_Associations_Collection
I'm not sure what else to try. Also, when I reset the comments table so there is no data in it, the app still displays:
User:
Comment:
when it loops through even though there is no data in it. I think it has to do with the dynamic finder confused by the id, but I tried moving it all to the controller as mentioned here, retrieving username with find_by_id(comment.user_id).name not working, and I still am getting undefined method errors. Any ideas? Appreciate the insight. I am not using a comments gem, am developing in cloud9, and am using PostgreSQL.
I found the issue in this post: Using <%= render comments %> always outputs an empty partial, even if there is nothing in the database
"The issue is that the form is above the <%= render #post.comments %> so there is an empty comment when you reach the partial for all the comments, even if there's none in database, put the <%= render "comments/form" %> below to fix this."

How do you create a rails app without using all of resource in create,update,delete?

In the rails guides tutorial creating a blog app after we create the rails app and create a resources in the routes then we start working on a form_for for creating a posts title and text in the guide it tells me that we need to add this line <%= form_for :post, url: posts_path do |f| %>
the posts_path helper is passed to the :url option. What Rails will do with this is that it will point the form to the create action of the current controller, the PostsController, and will send a POST request to that route.
so what am trying to understand is the passing to 'create action' you see I have a simple app where i want is when a text is entered in the title field and the submit button is entered I want it to pass to the create action where I just out put the text in the create action view or another view, the rails guide goes through teaching the 'CRUD' but I just want to understand How to build an app that doesn't use 'CRUD' for instance an app that takes an input and outputs it in another view?
my form:
<h1>Here Lets create a simple post</h1>
<%= form_for :post, url: posts_path do|f| %>
<p>
<%= f.label :title %>
<%= f.text_field :title %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
posts controller:
class PostsController < ApplicationController
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
end
def post_params
params_require(:post).permit(:title)
end
end
create view:
<h1>THis is the post create action</h1>
<%= #post.title %>
routes:
Learnnobase::Application.routes.draw do
resources :posts
root "welcome#home"
end
Right now am getting an error stating uninitialized constant PostsController::Post highlighting my create method? I've done so many rails app tutorials using 'CRUD' I really wanna learn building a simple app without using 'CRUD', I was trying to experiment with this app even though I do use the create action of "CRUD".
We generally use Rails to build database-backed applications, but for learning purposes, you can do it this way.
The problem you are facing here is: You are tyring to create an object of the Post class, that will be the model in the example you are referring to. The error comes up since you have not created the Post model.
To meet your requirement you can make your create action be:
def create
#post = post_params #this will be a hash
end
Then change your view to:
<h1>THis is the post create action</h1>
<%= #post[:title] %>
Since you have started with rails, I would ask you how did your posts/new page load with #post = Post.new in posts/new action when you do not have post model file and class?
It is not possible. Second, with what Manoj Monga has suggested you to use params by assigning it to an instance variable(wrong way to do so with params), if you try to use create_path for posts resources which literally is '/posts' you would end up hitting posts/index action.
Rails has standard reserve action names like :index(GET, /posts), :show(GET, /posts/:id), :new(GET, /posts/new), :create(POST, /posts), :edit(GET, /posts/:id/edit), :update(PATCH, /posts/:id) You should not attempt at overriding their purpose.
What I understand that you did use post model class and loaded posts/new page, then you deleted post model class and tried with what you have asked about in your question. You should respect Rails' standards.

Nested resource issue

I am struggling to pass an id successfully into my URL for the nested resource I have set up called Jobs.
The error I am getting when I try to pass the #job object into my link is as follows:
No route matches {:action=>"edit", :controller=>"jobs", :user_id=>1, :id=>nil}
Which clearly shows it can't find the id correctly and so is finding nil
At the moment I have my routes setup as so:
resources :users do
resources :jobs
end
and the link I have is <%= link_to "Edit", edit_user_job_path(#user.id,#job) %>
What is interesting is that if I pass the object #jobs with an 's' on the end it will load the page correctly but when I click on the link will try and add all of that users job id's.
In my controller for edit I have:
def edit
#user = current_user
#job = #user.jobs.find(params[:id])
end
Any help really would be much appreciated :)
UPDATE
Okay I was defining the object on the wrong page of my controller (under edit instead of index). The issue I am now having is Couldn't find Job without an ID
I updated my controller index definition to:
def index
#user = current_user
#jobs = #user.jobs.all
#job = #user.jobs.find(params[:id])
end
And have in my view (jobs#index)
<% #jobs.each do |f| %>
...
<%= link_to "Edit", edit_user_job_path(#user.id,job) %>
...
<% end %>
Any advice would be much appreciated if you know where I am going wrong :)
That error means that #job is nil.
The link is to the edit path, and the controller code you've provided is from the edit action in the controller. It seems unlikely that the edit page links to itself.
Look at the code that's actually rendering that page (it will appear in your stack trace) and you'll find that #job is not set. I suspect that you are on the index page and have something like:
<% #jobs.each do |job| %>
...
<%= link_to "Edit", edit_user_job_path(#user.id,#job) %>
...
<% end %>
If that is the case, then the link should be to job, not #job, i.e.
<%= link_to "Edit", edit_user_job_path(#user.id,job) %>
(expanding on iHiD's comment with his own post)
Using the restful resources means that you are going with the rails defaults, which consequently means that the index page gives you a list of all Jobs, and by default no single special job. If you run rake routes from the command line, you get all the routes, with parameters that are set from the URI. It should give you something like this:
user_jobs GET /users/:user_id/jobs(.:format) jobs#index
As you can see, there is no :id (params[:id]) for the index action.

Resources