I do this in my edit functions , update, destroy
#post = Post.friendly.find(params[:id])
if #post.user_id == current_user.id
there any way to optimize and make a single function, you used to like this:
before_action :set_user_post, only: [:edit, :update, :destroy]
private
def set_user_post
#post = current_user.posts.find_by(id: params[:id])
end
But add the friendly_id gem and modify it as follows:
private
def set_user_post
#post = current_user.posts.friendly.find(id: params[:id])
end
But it gives me error.
error:
Mysql2::Error: Unknown column 'id.id' in 'where clause': SELECT `posts`.* FROM `posts` WHERE `posts`.`user_id` = 1 AND `id`.`id` = 'primero' LIMIT 1
The find method finds a record by id and you can only pass a single id or an array of ids as input. But in your method, you're passing a hash. Modify your set_user_post method as
def set_user_post
begin
#post = current_user.posts.friendly.find(params[:id])
rescue ActiveRecord::RecordNotFound
redirect_to root_path, alert: 'You are knocking at the wrong door'
end
end
If a user's trying to access another user's post, the find method will raise an exception cause we're finding the posts of the current_user. We can rescue the exception and redirect the user to the home page with a
warning flash message.
EXTRA
You can also find a record using find_bymethod and pass it a hash. This method is used to find a record with any field(not just id). It returns the first record which matches the query.
For example,
def set_user_post
#post = current_user.posts.friendly.find_by(id: params[:id])
end
This does the same thing but the difference is that find raises an ActiveRecord::RecordNotFound exception if a record doesn't exist with the given id while find_by returns nil if a record doesn't exist.
For more, see http://apidock.com/rails/ActiveRecord/FinderMethods/find
Related
I'm attempting to create a shopping cart on my Rails 7 app, but for some reason, it's not working.
The basic setup is there are many products. When a new session is created, a blank order should be created, to which a customer can add order_items (which is basically a has_many :through to join products and orders), with #order representing the current order that is active at any given session.
The problem is that #order.id is coming up as nonexistant...but it's not nil...because #order doesn't actually exist. I'm not sure why this is happening because the set_order method should get called before everything.
I have the following in my application_controller.rb:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
before_action :set_order
private
def set_order
#order = Order.find(session[:order_id])
rescue ActiveRecord::RecordNotFound
#order = Order.create
session[:order_id] = #order.id
#order
end
end
Can anyone see where I'm going wrong here? I've looked at a bunch of other SO posts and all of it seems similar to what I have.
I am trying to create a simple app in Rails, where a user can list to-do items and delete them once completed. I'm having trouble with being able to destroy items. Each time I try this, the browser gives the following error:
ActiveRecord::RecordNotFound in UsersController#destroy Couldn't find Item with 'id'=11
I've tried various edits to the controller and _item partial.
Here are a couple links of some previous stack overflow questions/answers that I've tried to implement in order to fix this:
ActiveRecord::RecordNotFound - Couldn't find User without an ID
Couldn't find <Object> without an ID (Deleting a record)
I am using devise, Rails 5.0.0.1, and Ruby 2.3.1 (if that helps).
Here's my code:
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
end
def destroy
Item.find(params[:id]).destroy
end
end
class ItemsController < ApplicationController
def create
#item = current_user.items.new(items_param)
if #item.save
flash[:notice] = "Item was saved successfully."
redirect_to current_user
else
flash.now[:alert] = "Error creating item. Please try again."
render :new
end
end
def destroy
#item = Item.find(params[:id])
#item.destroy
end
private
def items_param
params.require(:item).permit(:name)
end
end
Here is the item partial _item.html.erb:
<%= content_tag :div, class: 'media', id: "item-#{item.id}" do %>
<%= link_to "", #item, method: :delete, class: 'glyphicon glyphicon-ok' %>
<%= item.name %>
<% end %>
Routes.rb:
Rails.application.routes.draw do
devise_for :users
resources :users, only: [:show, :destroy] do
resources :items, only: [:create, :show, :destroy]
end
root 'users#show'
end
Browser Error:
ActiveRecord::RecordNotFound in UsersController#destroy Couldn't find Item with 'id'=11
What am I doing wrong?
Maybe this can help you:
Rails 2: Model.find(1) gives ActiveRecord error when id 1 does not exist
Basically: If the db raise an internal error tying to find the record, then Rails raise the error RecordNotFound. That does not means that the record doesn't exist, it means that Rails was not able to get it. maybe you need to look at your db
This record does not exist in your database, No user present with ID = 11
This is not any issue , its mistake and you can read this about rails guide and blogs
http://guides.rubyonrails.org/active_record_basics.html
http://api.rubyonrails.org/classes/ActiveRecord/RecordNotFound.html
Do
rails c
>> User.all # Write User.all it will give you all records from db
and in this way you can check the existing records in your users table
And correct you method destory in users_controller
def destroy
Item.find(params[:id]).destroy
end
It should be
def destroy
User.find(params[:id]).destroy
end
I'm not too sure what's gone on, but basically in my reviews table in my database I did the following migration:
def change
remove_column :reviews, :name, :string
add_column :reviews, :user_id, :integer
end
So remove the name column and added the user_id column. I then ran rake db:migrate and rake db:setup, opened up the rails server through rails s and am now having this error:
TypeError in ProductsController#index
can't convert nil into String
def record_not_found
flash[:alert] = "Cannot find record number " + params[:id] + ".
Displaying all records."
redirect_to root_path
end
I am not really too sure what's gone on and what the problem is, the about code it's complaining about is in my application_controller.rb:
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
# make these methods available / visible in views
helper_method :the_date, :active_menu, :admin? , :logged_in?, :logged_in_as, :acting_role
# from an error generated when a request is
# made for a record with an 'id' that does not exist
rescue_from ActiveRecord::RecordNotFound,
:with => :record_not_found
private # these methods below can only be called by the object itself
def record_not_found
flash[:alert] = "Cannot find record number " + params[:id] + ".
Displaying all records."
redirect_to root_path
end
Products_controller.rb :
class ProductsController < ApplicationController
# When this controller is called, this method is always run first.
# The method 'set_product' found below, will be called for 'only' those
# actions indicated. Used to retrieve object data from the database.
before_action :set_product, only: [:show, :edit, :update, :destroy]
before_filter :check_authorization, except: [:index, :show, :search ]
# GET /products
# This action uses the class method 'all' sent to the classs Product to get all products
# similar to "SELECT * FROM PRODUCTS" , "#products" represents a collection of different
# product objects. Notice it is plural. Ordered by product title.
def index
# #products = Product.all.order :title
#products = Product.order(:title).page(params[:page]).per(6)
end
# GET /products/1
# The 'before_action' method above causes the private set_product' method to be called.
# The class method 'find' is sent to the Product class to find an existing product by
# its id. The retrieved database record is used to create an instance variable #product .
# The associated view 'show.html.erb' is called - using the instance variable #product .
def show
end
# GET /products/new
# A new empty Product object '#product' is created, all attributes are blank.
# This empty instance variable is sent to the view 'new.html.erb', #product is
# used in the blank form when entering new values.
def new
#product = Product.new
end
# GET /products/1/edit
# The 'before_action' method above causes the private set_product' method to be called.
# The class method 'find' is sent to the Product class to find an existing product by
# its id. The retrieved database record is used to create an instance variable #product .
# The associated view 'edit.html.erb' is called - using the instance variable #product,
# #product is used in the blank form when editing existing values.
def edit
end
# POST /products
# product_params is a hash object with all attribute values populated from a form used
# in 'new' above. The attributes in product_params are used in a new method to create
# a new product object. If the object's values are saved to the database then a flash
# notice is displayed, else the 'new' action is called again so a user can alter any errors.
def create
#product = Product.new(product_params)
if #product.save
redirect_to #product, notice: 'Product was successfully created.'
else
render action: 'new'
end
end
# PATCH/PUT /products/1
# this update action is run after a form is used to edit a record.
# The 'before_action' method above causes the private 'set_product' method to be called
# which instantiates a #product object from the database. This object is then updated with
# a call to product_params. The private method 'product_params'checks that the attributes
# used from the form are permitted.
# If successful this action redirects the user to show.html.erb or it will again
# render / display the edit form to correct any invalid data
# When editing, the file_field img_url textbox holds the value of a product's newly
# browsed filename, while the textbox img_url displays any existing filename.
# If a new filename has not been selected the file_field will remain empty but will
# be used to update the product's record.
def update
# temp_url_string is used to temporarily save from the database, an existing product's
# img_url filename.
temp_url_string = Product.find(params[:id]).img_url
if #product.update(product_params)
# if product's img_url attribute from the form is blank
if #product.img_url.empty?
# then a copy of the filename string is assigned to the img_url attribute
#product.update_attribute(:img_url, temp_url_string)
end
# redirect_to #product, notice: 'Product was successfully updated.'
# redirect_to #product, notice: "'" + #product.title + "'" + " was successfully updated."
redirect_to #product, notice: "'#{#product.title}' was successfully updated."
else
render action: 'edit'
end
end
# DELETE /products/1
# The 'before_action' method above causes the private set_product' method to be called.
# The class method 'find' is sent to the Product class to find an existing product by
# its id. The retrieved database record is used to create an instance variable #product .
# This object is then sent the message 'destroy' to delete the record from the database.
# A redirection method, redirects to the products_path (products_url) which means ... products#index
def destroy
#product.destroy
redirect_to products_url
end
# 'fuzzy_search' assigns to an instance variable collection '#products' all objects which include some
# of the search_string in their title, the collection is ordered by title.
# If there are some products to display, this action redirects the user to the 'index' action.
def search
# #products = Product.simple_search(params[:search_string])
products = Product.fuzzy_search2(params[:search_string])
#products = Kaminari.paginate_array(products.order :title).page(params[:page]).per(6)
if products.empty?
flash.now[:alert] = "No records found - displaying all records ..."
##products = Product.all.order :title
#products = Product.order(:title).page(params[:page]).per(6)
end
render :action => "index"
end
def multi_find
# call a Product class method, using two parameters; a category unique identifier and a search string (author or title)
products = Product.multi_find(params[:cat_id], params[:search_string])
#
#products = Kaminari.paginate_array(products.order :title).page(params[:page]).per(6)
# if no products have been found
if products.empty?
# display a notice
flash.now[:alert] = "No records found - displaying all records ..."
# then display all products
#products = Product.order(:title).page(params[:page]).per(6)
end
# use the index view
render :action => "index"
end
private
# The 'before_action' method above causes the private 'set_product' method to be called.
# The class method 'find' is sent to the Product class to find an existing product by
# its id, the retrieved database record is used to create an instance variable #product .
# This class method 'find' is similar to "SELECT * FROM PRODUCTS WHERE PRODUCT.ID = params[:id]"
def set_product
#product = Product.find(params[:id])
end
# This private method is called by the actions; create and update.
# 'product_params' checks that only permitted attributes are allowed.
# A hash 'params' of these parameter attributes and associated values is returned.
def product_params
params.require(:product).permit(:title, :description, :img_url, :price, :date_published, :author_name, :stock_level,:genre)
# returns 'params' a hash collection of keys and associated values.
end
end
looks like you have an ActiveRecord::RecordNotFound error in ProductsController#index,
so method record_not_found called with params[:id] = nil,
which in turn causes an TypeError at this line:
flash[:alert] = "Cannot find record number " + nil + ".
Displaying all records."
anyway for a more exact answer need to look at the ProductsController
I am trying to use a _before_filter_ in my ApplicationController to fetch a user object matching a user_id in a http parameter like:
before_filter :fetch_user
def fetch_user
if params[:user_id].present?
#user = User.find(params[:user_id])
end
rescue ActiveRecord::RecordNotFound
# user not found
end
This is working for me in all controllers which inherit from ApplicationController except the controller which is called UsersController in which #user seems to be set to nil in some way.
What could be the reason for this behavior? And is this the standard behavior? How to avoid/disable it?
UPDATE:
I always pass a parameter called user_id to the controller.
If I include the exact same before filter directly into the UsersController it is working!
there are no other before filters in the UsersController
UPDATE 2:
Route which is use to users controller
match ':user_id' => 'users#show'
User Controller code:
def show
if #user
render :text => "user not nil"
else
render :text => "user nil"
end
end
There is definitely a user with the id passed at the user_id parameter because
Thanks for your help!
point.1 in UsersController, you get params[:id] as user_id
point.2 use find_by_id to avoid rescue ActiveRecord::RecordNotFound, it safely returns nil
and so...
def fetch_user
user_id = controller_name=='users' ? params[:id] : params[:user_id]
#user ||= User.find_by_id user_id
end
Rails 3.0.3
ruby 1.9.2p0
The Problem:
I have a Users table which has many items, the item(s) in turn therefore belongs to the Users.
In my model item.rb i attempt to save the item along with the value for the user.id so i have:
self.User_ID = #user.id
this however give me the error
Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id
this is causing some confusion that it can't find this as in the show.html.erb that 'wraps' this page <%= #user.id %> displays the correct ID on the page
Many thanks in advance
** EDIT **
The Shorten action is the action upon which i want to parameter to be passed
class ItemsController < ApplicationController
def redirect
#item = Item.find_by_shortened(params[:shortened])
if #item
#redirect_to #item.original
redirect_to #item.original
else
redirect_to :shorten
end
end
def shorten
#host = request.host_with_port
#user = current_user
You need to load the #user model in every action that will require access to it. Having it render properly in the show action will not guarantee it is loaded in the update action.
Usually you need to have something like this in your controller:
class UsersController < ApplicationController
before_filter :load_user, :except => [ :index, :new, :create ]
# ...
protected
def load_user
#user = User.find(params[:user_id] || params[:id])
rescue ActiveRecord::RecordNotFound
render(:text => 'Record not found')
end
end