Couldn't find Product with 'id'=search - ruby-on-rails

I'm just starting with RoR and i got an issue.
Earlier, I asked hear and nobody could fix it. I would like to make a simple search form, where i would search for a product name(title).
Here is the issue: "Couldn't find Product with 'id'=search"
Picture with the error
Here is my controller:
class ProductsController < ApplicationController
before_action :set_product, only: [:show, :edit, :update, :destroy]
helper_method :get_cost
# GET /products
def index
#products = Product.all
#products = Product.search(params[:find])
end
# GET /products/1
def show
end
# GET /products/new
def new
#product = Product.new
# ingredients_ids = #product.ingredients
end
# GET /products/1/edit
def edit
end
# POST /products
def create
#product = Product.new(product_params)
if #product.save
redirect_to #product, notice: 'Product was successfully created.'
else
render :new
end
end
# PATCH/PUT /products/1
def update
if #product.update(product_params)
redirect_to #product, notice: 'Product was successfully updated.'
else
render :edit
end
end
# DELETE /products/1
def destroy
#product.destroy
redirect_to products_url, notice: 'Product was successfully destroyed.'
end
private
# Use callbacks to share common setup or constraints between actions.
def set_product
#product = Product.find(params[:id])
end
# Only allow a trusted parameter "white list" through.
def product_params
params.require(:product).permit(:title, :description, :category, :price, :quantity, {ingredient_ids: []})
end
end
Here is my model:
class Product < ActiveRecord::Base
has_and_belongs_to_many :ingredients
has_and_belongs_to_many :orders
enum category: ["Culinária Italiana", "Culinária Oriental", "Culinária Árabe", "Culinária Brasileira"]
TITLE_MIN_LENGTH = 3
DESCRIPTION_MIN_LENGTH = 2
validates :title, presence: true, :length => {:minimum => TITLE_MIN_LENGTH}, uniqueness: true
validates :description, presence: true, :length => {:minimum => DESCRIPTION_MIN_LENGTH}
def self.search(search)
if search
where(["title LIKE ?", "%#{search}%"])
else
all
end
end
end
here is my view:
<%= form_tag(products_search_path, :method => :get) do%>
<%= text_field_tag :find, nil, placeholder:"Insira o que está procurando"%>
<%= submit_tag "Pesquisar", :name => nil %>
<% end %>
And just to finish, here is my routes:
Rails.application.routes.draw do
get 'sessions/new'
get 'users/new'
get 'orders/show'
get 'orders/new'
resources :ingredients
resources :products do
get 'search'
end
resources :orders
root "home#index"
get '/login', to: 'sessions#new'
post '/login', to: 'sessions#create'
delete '/logout', to: 'sessions#destroy'
get '/signup', to: 'users#new'
post '/signup', to: 'users#create'
get 'home/about'
get 'home/contact'
get "home" => "home#index"
end
Thanks for the attention, Miguel.

You have a get 'search' in your routes.rb, but there is not def search in your controller. So it thinks you're trying to access the show page:
GET products/[id] where the [id] is search (which is clearly invalid, since all ids are numbers).
If you want to keep that search route, then you should set it as:
get 'search', on: :collection. And add def search to your controller with your search logic.
Edit:
Just adding a few tips:
In the def index method, this line #products = Product.all is unnecessary, since you overwrite it in the following line;
Instead of creating a different route for the search, it's recommended that you use the index with a query string. So you should:
remove the get 'search' from the routes.rb;
change your search form path to products_path instead of products_search_path;

search is a collection method, so the route needs to be...
resources :products do
collection do
get 'search'
end
end

Related

How should I update a resource that is fully depend on other resource

Let's say I have those two models:
class Post < ApplicationRecord
belongs_to :site
end
class Site < ApplicationRecord
has_many :posts
end
In order to create a post, I need to know the site id. Right now I have a route that points to PostsController#create:
post 'posts', to: 'posts#update'
Should I expect the user to send the site_id in the body of the request?
# config/routes.rb
resources :sites do
resources :posts
end
This creates nested routes. Run $ rails routes to see the routes created.
Should I expect the user to send the site_id in the body of the request?
No. A nested route describes the relationship between the two resources. Its very obvious by looking at the path that POST /sites/1/posts will create a post belonging to a site.
It would be ok to pass a site id in the params if you are using shallow nesting and the user can change which site a post belongs to when updating.
# app/controllers/posts_controller.rb
class PostsController
before_action :set_site
before_action :set_post, only: [:show, :edit, :update]
# GET /sites/1/posts/1
def show
end
# GET /sites/1/posts
def index
#posts = #site.posts
end
# GET /sites/1/posts/new
def new
#post = #site.posts.new
end
# POST /sites/1/posts
def create
#post = #site.posts.new(post_params)
if #post.save
redirect_to #post
else
render :new
end
end
# PATCH|PUT /sites/1/posts
def update
if #post.update(post_params)
redirect_to #post
else
render :edit
end
end
# GET /sites/1/posts/edit
def edit
end
private
def set_site
#site = Site.includes(:posts).find(params[:site_id])
end
def set_post
#post = #site.posts.find(params[:id])
end
def post_params
params.require(:post).permit(:title) # ...
end
end
# app/views/posts/_form.html.erb
<%= form_for [#site, #post] do |f| %>
# ...
<% end %>
# app/views/posts/new.html.erb
<%= render partial: 'form' %>
# app/views/posts/edit.html.erb
<%= render partial: 'form' %>

Cannot access "Current user" in rails

I am using devise and devise_ldap for my rails authentication. I am trying to use the built in helper, current user to display the users email on the welcome page of my application.
This is the code that I have tried to use to:
<% if user_signed_in? %>
<div>Signed in as... <%= current_user.email %></div>
<% end %>
when I sign in to the application, I get the error;
undefined method `email' for nil:NilClass
Here is my routes.rb
Rails.application.routes.draw do
devise_for :users
resources :users
resources :systems do
member do
get :targets, :sources
end
root 'systems#index'
end
and my users controller:
class UsersController < ApplicationController
authorize_resource
before_action :set_user, only: [:show, :edit, :update, :destroy]
# GET /users
def index
#users = User.all.order("display_name asc")
end
# GET /users/1
def show
end
# GET /users/new
def new
#user = User.new
end
# GET /stories/1/edit
def edit
respond_to do |format|
format.html
format.js
end
end
# POST /stories
def create
#user = User.new(user_params)
respond_to do |format|
puts 'user controller'
if #user.save!
format.html { redirect_to user_path(#user), notice: 'User was successfully created.' }
else
format.html { render :new }
end
end
end
# PATCH/PUT /stories/1
def update
respond_to do |format|
if #user.update(user_params)
format.html { redirect_to user_path(#user), notice: 'User was successfully updated.' }
else
format.html { render :edit }
end
end
end
# DELETE /stories/1
def destroy
#user.destroy
respond_to do |format|
format.html { redirect_to users_path notice: 'User was successfully destroyed.' }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_user
#user = User.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params.require(:user).permit(:display_name, :email, :username)
end
end
my users model:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
before_create :rememberable_value
before_save :get_ldap_values
devise :ldap_authenticatable, :rememberable, :trackable, :validatable
def get_ldap_values
if self.username
self.email = Devise::LDAP::Adapter.get_ldap_param(self.username,"mail").first if Devise::LDAP::Adapter.get_ldap_param(self.username,"mail")
self.display_name = Devise::LDAP::Adapter.get_ldap_param(self.username,"displayName").first if Devise::LDAP::Adapter.get_ldap_param(self.username,"displayName")
end
end
# def role?(role)
# return !!self.roles.find_by_name(role.to_s.camelize)
# end
def email_required?
false
end
def email_changed?
false
end
def rememberable_value
self.remember_token ||= Devise.friendly_token
end
def name_to_display
if self.display_name
self.display_name
else
self.username
end
end
def password_required?
false
end
def password_match?
self.errors[:password] << "can't be blank" if password.blank?
self.errors[:password_confirmation] << "can't be blank" if password_confirmation.blank?
self.errors[:password_confirmation] << "does not match password" if password != password_confirmation
password == password_confirmation && !password.blank?
end
end
I am not sure what I am missing to be able to access the current users information after a successful sign in.
Update
Here is the new routes file:
Rails.application.routes.draw do
devise_scope :user do
get '/users/sign_out' => 'devise/sessions#destroy'
get "/users/sign_in" => "devise/sessions#new"
# delete "/logout" => "devise/sessions#destroy"
end
devise_for :users
authenticate(:user) do
resources :users
resources :reports
resources :change_logs, only: [:index, :show]
resources :systems do
member do
get :targets, :sources
end
resources :change_logs, module: :systems
resources :components do
resources :change_logs, module: :components
end
resources :c_relations
end
resources :integrations
get '/static_pages/home' # => 'static_pages#home', as: 'home'
root 'systems#index'
end
In routes.rb you should enclose the rows following
devise_for :users
in a block
authenticate(:user) do
resources :users
[...]
end
The problem was that I had overridden the devise mapping and current_user. I removed them and was able to access current user in my views.
Do you have before_action :authenticate_user! in your controller chain at all?
Current_user could be nil after signin is if you aren't asking devise to authenticate the action.

routes error in rails

I am working on a project. I am making an application where a user can add an issue (like a post) and the user can comment on it.
on running this application, I get an error
Couldn't find Issue with 'id'=show
the code for routes file is
resources :issues do
resources :comments
end
get 'users/new'
get 'users/create'
get 'users/show'
get 'users/edit'
get 'issues/show/:id', :to => 'issues#show'
resources :users
resources :sessions, :only => [:create, :new,:destroy]
get '/signup', :to => 'users#new'
get '/signin' , :to => 'sessions#new'
get '/signout', :to => 'sessions#destroy'
the code for the issues controller is
class IssuesController < ApplicationController
def new
#issue = Issue.new
end
def create
#issue = Issue.new(issues_params)
if #issue.save
flash[:success]='your issue has been raised'
redirect_to :controller => 'issues', :action => 'show', :id => #issue.id
else
render 'new'
end
end
def edit
#issue = Issue.find(params[:id])
end
def update
#issue = Issue.find(params[:id])
if #issue.update_attributes(issues_params)
redirect_to :controller => 'issues', :action => 'show', :id => #issue.id
else
render 'edit'
end
end
def index
#issues = Issue.all
end
def show
#issue = Issue.find(params[:id])
end
def destroy
#issue=Issue.find(params[:id])
#issue.destroy
redirect_to :controller => 'issues', :action => 'index'
end
protected
def issues_params
params.require(:issue).permit(:title,:content)
end
end
the code for the comments controller from where I call the show method in issues controller is
class CommentsController < ApplicationController
def create
#issue = Issue.find(params[:issue_id])
#comment = #issue.comments.create(comment_params)
if #comment.save
redirect_to :controller => 'issues', :action => 'show', :id => #issue[:id]
else
render 'new'
end
end
private
def comment_params
params.require(:comment).permit(:content)
end
end
You must be trying to request the URI /issues/show? This will map to the GET /issues/:id from the resources :issues do line of your routes. The router will set the params[:id] to the string "show" and send the request to the show action of the IssuesController which, as you've shown, will then try to do Issue.find(params[:id]) ie. Issue.find("show") and hence you get your error.
Change this
resources :issues do
resources :comments
end
to
resources :issues, except: [:show] do
resources :comments
end
It will resolve your problem!

Adding acts_as_votable voting to posts and comments, routing issue?

I am trying to use acts_as_votable voting system on both posts and comments in my rails app. I am currently generating some obviously improper routes for my comments#upvote and comments#downvote, Here they are below:
upvote_post PUT /posts/:id/upvote(.:format) comments#upvote
downvote_post PUT /posts/:id/downvote(.:format) comments#downvote
But they routes need to be something like /posts/comment/:id/downvote. Here is how I am currently doing my routes
resources :posts do
member do
put "like", to: "posts#upvote"
put "dislike", to: "posts#downvote"
end
resources :comments
member do
put "upvote", to: "comments#upvote"
put "downvote", to: "comments#downvote"
end
end
Also, will I need two votes tables since I want both comments and posts to be votable?
Here is my my comments controller if needed:
class CommentsController < ApplicationController
before_filter :authenticate_user!, :except => [:index, :show]
def index
#post = Post.find(params[:post_id])
#user = User.find(params[:user_id])
#comments = #post.comments.order('created_at desc')
end
def new
#post = Post.find(params[:post_id])
#comment = #post.comments.new(params[:id])
end
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.create(comment_params)
#comment.post_id = #post.id
#comment.user_id = current_user.id
if #comment.save
redirect_to post_comments_path(#post)
else
redirect_to new_post_comment_path(post)
end
end
def destroy
end
def upvote
#post = Post.find(params[:post_id])
#comment = #post.comments.find(params[:id])
#comment.upvote_by current_user
redirect_to post_comments_path(#post)
end
def downvote
#post = Post.find(params[:post_id])
#comment = #post.comments.find(params[:id])
#comment.downvote_by current_user
redirect_to post_comments_path(#post)
end
private
def comment_params
params.require(:comment).permit(:body, :post_id, :user_id)
end
end
Thanks for the help
As a rule you probably don't want to nest your routes so deep. And the comment vote doesn't need to know the id of the post, just the comment. You also might find that rather than have a separate method for up and down voting in the controller having the votes go to the VotesController and just handle it there
So, I would do something like this:
resources :posts do
resources :comments, only: [:new, :create, :destroy]
resources :votes, only: [:create, :update, :destroy]
end
resources :comment do
resources :votes, only: [:create, :update, :destroy]
end
That's if you want to have votes be a polymorphic relation on both in which case in your ApplicationsController you'd want a method like:
def find_model
params.each do |name, value|
if name =~ /(.+)_id\z/
return $1.classify.constantize.find(value)
end
end
nil
end
# VotesController
def create
model = find_model
if model
# do stuff
end
end
If you have separate votes tables you can skip this last part.
Had a similar problem fixed it by changing
put "like", to: "posts#upvote"
put "dislike", to: "posts#downvote
to
get "like", to: "posts#upvote"
get "dislike", to: "posts#downvote"
posts_controller
def upvote
#post.upvote_by current_user
redirect_to :back
end
def downvote
#post.downvote_by current_user
redirect_to :back
end
post show page
<%= link_to "like", like_post_path(#post), method: :get %>
<%= link_to "dislike", dislike_post_path(#post), method: :get %>
hope this helps

Can't find user without ID - form error in Rails 4 project

I'm working on "Edit profile" part with Ruby on Rails.
the route.rb is:
Rails.application.routes.draw do
get 'courses/index'
get 'courses/new'
get 'courses/edit'
get 'courses/show'
get 'course/index'
get 'course/new'
get 'course/edit'
get 'course/show'
get 'sessions/login'
get 'sessions/main'
get 'sessions/profile'
get 'sessions/setting'
get 'users/new'
get 'home/index'
resources :users
resources :sessions
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".
# You can have the root of your site routed with "root"
root 'home#index'
# Example of regular route:
# get 'products/:id' => 'catalog#view'
# Example of named route that can be invoked with purchase_url(id: product.id)
# get 'products/:id/purchase' => 'catalog#purchase', as: :purchase
# Example resource route (maps HTTP verbs to controller actions automatically):
resources :courses
# Example resource route with options:
# resources :products do
# member do
# get 'short'
# post 'toggle'
# end
#
# collection do
# get 'sold'
# end
# end
# Example resource route with sub-resources:
# resources :products do
# resources :comments, :sales
# resource :seller
# end
# Example resource route with more complex sub-resources:
# resources :products do
# resources :comments
# resources :sales do
# get 'recent', on: :collection
# end
# end
# Example resource route with concerns:
# concern :toggleable do
# post 'toggle'
# end
# resources :posts, concerns: :toggleable
# resources :photos, concerns: :toggleable
# Example resource route within a namespace:
# namespace :admin do
# # Directs /admin/products/* to Admin::ProductsController
# # (app/controllers/admin/products_controller.rb)
# resources :products
# end
match '/about', to: 'home#about', via: 'get'
match '/signup', to: 'users#new', via: 'get'
match ':controller(/:action(/:id))(.:format)', via: 'get'
match '/signin', to: 'sessions#new', via: 'get'
match '/signout', to: 'sessions#destroy', via: 'delete'
match '/main', to: 'users#new', via: 'get'
#match '/profile', to: 'sessions#profile', via: 'get'
match '/setting', to: 'sessions#setting', via: 'get'
match '/editname', to: 'users#edit', via: 'get'
match '/show', to: 'users#show', via: 'get'
match '/profile', to: 'users#profile', via: 'get'
#match '/info', to: 'users#info', via: 'get'
#match '/changepass', to: 'users#edit', via: 'get'
end
My users_controller.rb is:
class UsersController < ApplicationController
before_filter :check_if_signned_in, only: [:show, :delete]
before_filter :signed_in_user, only: [:edit, :update]
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
redirect_to #user, notice: 'User was sucessfully created!'
else
render action: "new"
end
end
def show
#user = User.find(params[:id])
end
def edit
##user = User.find(current_user.id)
#user = User.find(params[:user_id])
end
def update
#user = User.find(params[:id])
if #user.update_attributes(user_params)
flash[:success] = "Profile updated."
sign_in #user_params
redirect_to #user
else
render 'edit'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
def signed_in_user
redirect_to signin_path, notice: "Please sign in." unless signed_in?
end
end
And, the sessions_controller.rb is:
class SessionsController < ApplicationController
def new
end
def create
user = User.authenticate(params[:session][:email], params[:session][:password])
if user.nil?
flash.now[:error] = "Invalid email or password."
render :new
else
sign_in user
redirect_to user
end
end
def destroy
sign_out
redirect_to signin_path
end
end
the edit.html.erb is:
Editing profile
<div class="row">
<div class="span6 offset3">
<%= form_for(#user) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation, "Confirm Password" %>
<%= f.password_field :password_confirmation %>
<%= f.submit "Update", class: "btn btn-large btn-primary" %>
<% end %>
</div>
</div>
the sessions_helper.rb is:
module SessionsHelper
def sign_in(user)
session[:user_id] = user.id
self.current_user = user
end
def current_user=(user)
#current_user = user
end
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
def signed_in?
!current_user.nil?
end
def sign_out
session[:user_id] = nil
self.current_user = nil
end
def current_user?(user)
user == current_user
end
def deny_access
redirect_to signin_path, :notice => "Please sign in first."
end
end
The error is: in the code below
def edit
***#user = User.find(params[:user_id])***
end
it Couldn't find User without an ID
How can i fix this problem please?
And moreover, the version of my rails is: 4.1.2, it seems the thing "update_attributes" doesn't work, is that true? How can I make "edit profile" function without using update_attributes please?
Thank you!
Routes
Firstly, you'll be much better DRYing up your routes:
#config/routes.rb
resources :courses, only: [:index, :new, :edit, :show]
resource :course, only: [:index, :new, :edit, :show] #-> singular resource (not sure if you want)
resources :sessions, path_names: {new: "signin", destroy: "signout"} do
collection do
get :login
get :main
get :profile
get :setting
end
end
resources :users, path_names: {new: "signup"} do
collection do
get "main", action: :new
end
end
resources :home, only: [], path: "" do
get :about
end
You have to remember Rails, and by virtue, its routing structure, is resource-based (resourceful). This means everything you do needs to be centered on an ActiveRecord Object (oft called a "resource") - this is why Rails' routing is based on resources :)
Your routes were NOT resource-based, and hence very confusing
--
Fix
When you receive the error:
Couldn't find User without an ID
It basically means you aren't passing the required ID parameter to your controller, hence preventing your application from being able to identify the object required to populate your form.
This will either be caused by not passing the params[:id] to your /profile controller, or you're calling the wrong variable name
-
I would initially look at your routes
You need to appreciate the importance of collection vs member routes - member routes are basically designed for individual element. I believe you're not passing the parameter your edit action needs, hence preventing your application from assigning a value to the #edit variable
You're either going to need to use a session to access the User.id, or use a member route (which will pass the id in the url)

Resources