NoMethodError (undefined method `locked' - ruby-on-rails

I get an error in my application on production envinronment at a random rate. When I restart the server the problem disappears for some time and then resurfaces.
This is the error
NoMethodError (undefined method `locked' for #<Class:0x00000006776a40>):
app/controllers/orders_controller.rb:29:in `rescue in new'
app/controllers/orders_controller.rb:29:in `new'
The Codesnipped looks like this:
#order.product_option = ProductOption.find_by_identifier(params[:product]) rescue ProductOption.first
For explanation. This snipped pre-selects the product option in the front-end.
The error occors in other areas and also related with the ProductOption model.
The model product_option looks like this:
class ProductOption < ActiveRecord::Base
attr_accessible :identifier, :price, :servings, :title
before_destroy :check_for_deps
has_many :users
has_many :orders
belongs_to :product
attr_accessible :product_id, :product, :price, :identifier, :servings, :color
validates_presence_of :identifier, :price, :product
validates_numericality_of :price, greater_than_or_equal_to: 1
validates_numericality_of :servings, greater_than_or_equal_to: 1
default_scope order('products.position, servings').includes(:product)
def title
I18n.t 'order_form.product_option_title',
recipe_count: self.product.recipe_count,
product_title: self.product.title,
servings: self.servings
end
def subtitle
self.product.subtitle
end
def pretty_price
'%.2f' % self.price
end
def check_for_deps
if users.count > 0
errors.add(:base, I18n.t('model.validation.product_has_still_objects_assigned'))
return false
end
if orders.count > 0
errors.add(:base, I18n.t('model.validation.product_has_still_objects_assigned'))
return false
end
end
end
This is product.rb:
class Product < ActiveRecord::Base
before_destroy :check_for_options
acts_as_list
translates :title, :subtitle, :description
active_admin_translates :title, :subtitle, :description do
validates_presence_of :title
end
attr_accessible :discount, :remarks, :title, :description, :subtitle, :product_options, :product_option_ids, :recipe_count
validates_presence_of :title
has_many :recipe_assignments
has_many :deliveries, through: :recipe_assignments
has_many :orders
has_many :product_options
default_scope order('position ASC')
private
def check_for_options
if product_options.count > 0
errors.add(:base, I18n.t('model.validation.product_has_still_objects_assigned'))
return false
end
end
end
I am using Rails v3.2.18
Troubleshooting
When I did some research I came accross this rails-issue #7421. But the issue was closed and declared as not being a bug.
According to #lifius i ran the following command:
culprit = :locked
ActiveRecord::Base.descendants.find {|e| e.singleton_methods.include?(culprit)}
# Result
Delivery(id: integer, delivery_date: date, remarks: text, created_at: datetime, updated_at: datetime, status: string)

You may execute the following:
Rails.application.eager_load!
ActiveRecord::Base.descendants.find {|e| e.singleton_methods.include?(:locked)}
in the rails console and see affected models.

Related

Upgrading attr_accessible from Rails 3 to Rails 4

I'm trying to systematically upgrade from rails 3 to rails 4 and all of my 25 models are based on attr_accessor! So before getting into that can anyone provide me a simple example on how to do this. I've read the documentation and other topics but it's not clear on how to do it since this is my first upgrade Rodeo.
class Settings < ActiveRecord::Base
image_accessor :favicon
attr_accessible :company_name, :show_hot_jobs, :show_students, :subheading, :show_testimonials, :show_on_boarding, :max_concurrent_applications
attr_accessible :image_uid, :max_concurrent_application_groups
attr_accessible :primary_color, :white_color, :gray_color, :opacity, :locale, :lang_nl, :lang_fr, :lang_de, :lang_en, :privacy_page
attr_accessible :show_evp, :show_contact_person, :show_jobs_for_you
attr_accessible :favicon, :favicon_uid, :remove_favicon, :retained_favicon
attr_accessible :home_url, :show_correspondence, :show_appointment
attr_accessible :sliderone_uid, :slidertwo_uid, :sliderthree_uid, :sliderfour_uid, :sliderfive_uid
attr_accessible :sliderone_link, :slidertwo_link, :sliderthree_link, :sliderfour_link, :sliderfive_link
attr_accessible :sliderone_testoverview, :slidertwo_testoverview, :sliderthree_testoverview, :sliderfour_testoverview, :sliderfive_testoverview
attr_accessible :sliderone_page, :slidertwo_page, :sliderthree_page, :sliderfour_page, :sliderfive_page
validate :any_lang_present?
validates :max_concurrent_applications, :numericality => { :greater_than_equal_to => 1 }
validates :max_concurrent_application_groups, :numericality => { :greater_than_equal_to => 1 }
# Fav Icon Validation
validates_property :ext, of: :favicon, :in => ['ico', 'png', 'gif']
has_paper_trail
has_many :setting_translations, :foreign_key => :setting_id
accepts_nested_attributes_for :setting_translations, :allow_destroy => true, :reject_if => :all_blank
attr_accessible :setting_translations_attributes, :allow_destroy => true
translates :subheading, :company_name, :image_uid, :home_url, :sliderone_uid, :slidertwo_uid, :sliderthree_uid, :sliderfour_uid, :sliderfive_uid
translates :sliderone_link, :slidertwo_link, :sliderthree_link, :sliderfour_link, :sliderfive_link
translates :sliderone_testoverview, :slidertwo_testoverview, :sliderthree_testoverview, :sliderfour_testoverview, :sliderfive_testoverview
translates :sliderone_page, :slidertwo_page, :sliderthree_page, :sliderfour_page, :sliderfive_page
attr_accessible can be converted like so:
From
class Settings
attr_accessible :home_url
accepts_nested_attributes_for :setting_translations
end
class SettingTranslation
attr_accessible :etc
end
To
class SettingsController
def create
#settings = Settings.new(settings_params)
# ...
end
private
def settings_params
params.require(:settings).permit(
:home_url,
:setting_translations_attributes => [:id, :_destroy, :etc]
)
end
end
Note, you have to include :_destroy if you want to allow destroy on that model (:allow_destroy => true), and you have to include all attributes that should be accessible from any nested attributes. Though you remove attr_accessible when you've permitted, you do not remove accepts_nested_attributes_for.
Just remove attr_accessible from model. and add permit params according to need in controller.
like below :
class SupportTicketsController < ApplicationController
def create
#support_ticket = SupportTicket.create(house_params)
......
end
private
def house_params
params.require(:support_ticket).permit(:subject, :message, ....)
end
end
and if you don't want to make this much changes then add "protected_attributes" gem https://github.com/rails/protected_attributes in your gemfile And everything would work as before.

How to show errors for relations on the main Model

I want to include errors from a rather deep assocation in a parent:
class Order < ActiveRecord::Base
has_many :line_items
end
class LineItem < ActiveRecord::Base
belongs_to :product, polymorphic: true
end
class Site < ActiveRecord::Base
has_one :line_item, as: :product, autosave: true
validates :domain, presence: true
end
Used as:
product = Site.new(domain: nil)
order = Order.new
order.line_items << LineItem.new(product: product)
order.valid? #=> false
product.valid? #=> false
product.errors? #=> { 'domain' => 'cannot be blank' }
Is there some rails way, or association-parameter to make the errors
bubble up so that I get:
order.errors #=> { 'domain' => 'cannot be blank' }
In other words, that the Order, the top of the association,
transparently proxies the validation errors from its children?
I am aware of using simple before_validation hooks, like so:
class Order < ActiveRecord::Base
before_validation :add_errors_from_line_items
private
def add_errors_from_line_items
self.line_items.each do |line_item|
line_item.product.errors.each do |field, message|
errors.add(field, message)
end unless line_item.product.valid?
end
end
end
end
But I am wondering if there is not some ActiveRecord feature that I am overlooking.

ActiveModel::MassAssignmentSecurity::Error even when using accepts_nested_attributes_for

My complete error message is:
ActiveModel::MassAssignmentSecurity::Error in
WorkoutsController#create Can't mass-assign protected attributes:
workout_entry
The params that I am sending looks like:
{"workout"=>{"unit"=>"kg", "name"=>"2013-02-20T21:26:19", "note"=>nil, "workout_entry"=> [{"workout_entry_number"=>"1", "exercise_id"=>2, "entry_detail"=>[{"set_number"=>"1", "weight"=>"32", "reps"=>"43"}]}]}}
I have a workout that has many workout entries and each workout entries can have many entry details. The note is optional.
workout.rb
class Workout < ActiveRecord::Base
has_many :workout_entries, dependent: :destroy
attr_accessible :id, :name, :note, :unit, :workout_entries_attributes
belongs_to :user
accepts_nested_attributes_for :workout_entries
validates_presence_of :name
validates_presence_of :unit, :inclusion => %w(kg lb)
validates_associated :workout_entries
default_scope order("created_at DESC")
end
workout_entry.rb
class WorkoutEntry < ActiveRecord::Base
belongs_to :workout
belongs_to :exercise
has_many :entry_details, dependent: :destroy
attr_accessible :workout_id, :exercise_id, :workout_entry_number, :entry_details_attributes
accepts_nested_attributes_for :entry_details
validates :exercise_id, presence: true, numericality: {only_integer: true}, :inclusion => { :in => 1..790 }
validates :workout_id, presence: true, numericality: {only_integer: true, greater_than_or_equal_to: 1}
validates :workout_entry_number, presence: true, numericality: {only_integer: true, greater_than_or_equal_to: 1}
end
workouts_controller.rb
class WorkoutsController < ApplicationController
respond_to :json
before_filter :authenticate_user!
def index
respond_with(current_user.workouts)
end
def show
respond_with(current_user.workouts.find(params[:id]))
end
def create
respond_with(current_user.workouts.create(params[:workout]))
end
def update
#workout = current_user.workouts.find(params[:id])
if #workout.update_attributes(params[:workout])
render json: #workout, status: :ok
else
render json: #workout.errors, status: :unprocessable_entity
end
end
def destroy
respond_with(current_user.workouts.destroy(params[:id]))
end
end
I tried switching the ordering of attr_accessible and accepts_nested_attributes_for within the workout.rb, but it does not work.
I even tried to set
config.active_record.whitelist_attributes = true
but creating was still prevented.
accepts_nested_attributes_for does not add any attributes to the whitelist. Whatever keys your trying to pass to update_attributes have to be listed in attr_accessible, in your case you need to add workout_entry to attr_accessible.
It does look like you have an error in the form, if your using fields_for then it should be using the key workout_entries_attributes, which you have accessible.
Try to add workout_entry_ids in attr accessible in your workout model.
I decided to not use accepts_nested_attributes_for in the workout and workout_entry models because it wasn't working for me. I also updated the format of my json that is sent. Details are in the link below
link

ActiveModel::MassAssignmentSecurity::Error in CustomersController#create (attr_accessible is set)

In my controller, I've got error when create action and try create model [can't mass-assignment], but
in my spec, my test of mass-assignment model its pass!?!
My Model:
class Customer < ActiveRecord::Base
attr_accessible :doc, :doc_rg, :name, :birthday, :name_sec, :address, :state_id, :city_id, :district_id,
:customer_pj, :is_customer, :segment_id, :activity_id, :person_type, :person_id
belongs_to :person , :polymorphic => true, dependent: :destroy
has_many :histories
has_many :emails
def self.search(search)
if search
conditions = []
conditions << ['name LIKE ?', "%#{search}%"]
find(:all, :conditions => conditions)
else
find(:all)
end
end
end
I`ve tired set attr_accessible in controller too, in my randomized way.
the Controller:
class CustomersController < ApplicationController
include ActiveModel::MassAssignmentSecurity
attr_accessible :doc, :doc_rg, :name, :birthday, :name_sec, :address, :state_id, :city_id, :district_id, :customer_pj, :is_customer
autocomplete :business_segment, :name, :full => true
autocomplete :business_activity, :name, :full => true
[...]
end
The test, my passed test
describe "accessible attributes" do
it "should allow access to basics fields" do
expect do
#customer.save
end.should_not raise_error(ActiveModel::MassAssignmentSecurity::Error)
end
end
The error:
ActiveModel::MassAssignmentSecurity::Error in CustomersController#create
Can't mass-assign protected attributes: doc, doc_rg, name_sec, address, state_id, city_id, district_id, customer_pj, is_customer
https://github.com/megabga/crm
1.9.2p320
Rails 3.2
MacOS
pg
my bad, in my controller its setting an oldest class. Then old class don`t have attributes passing in parameters. Sorry!

Rails 3.2 NoMethodError (undefined method `price=') in line_item using Agile book

I am following the Agile Web Development book tutorial with some small changes, halfway through Chapter 12 on Check Out.
I am getting the following error:
NoMethodError (undefined method `price=' for #<LineItem:0x00000103a0de18>):
app/models/cart.rb:11:in `add_deal'
app/controllers/line_items_controller.rb:45:in `create'
Here is my cart model:
class Cart < ActiveRecord::Base
# attr_accessible :title, :body
has_many :line_items, dependent: :destroy
def add_deal(deal_id)
current_item = line_items.find_by_deal_id(deal_id)
if current_item
current_item.quantity += 1
else
current_item = line_items.build(deal_id: deal_id)
current_item.price = current_item.deal.price
end
current_item
end
def total_price
line_items.to_a.sum { |item| item.total_price }
end
end
Here is my create action in line_items_controller with the relevant line 45 where it freezes:
def create
#cart = current_cart
deal = Deal.find(params[:deal_id])
#line_item = #cart.add_deal(deal.id)
My line item model:
class LineItem < ActiveRecord::Base
attr_accessible :cart_id, :deal_id, :quantity
belongs_to :order
belongs_to :deal
belongs_to :cart
def total_price
deal.price * quantity
end
end
Here is my deal model:
class Deal < ActiveRecord::Base
attr_accessible :description, :expiration, :featured, :image_url, :inventory, :price, :sold, :title, :value, :deal_id
has_many :line_items
before_destroy :ensure_not_referenced_by_any_line_item
validates :price, numericality: {greater_than_or_equal_to: 0.01}
validates :title, uniqueness: true
validates :title, :description, :image_url, presence: true
private
# ensure that there are no line items referencing this product
def ensure_not_referenced_by_any_line_item
if line_items.empty?
return true
else
errors.add(:base, 'Line Items present')
return false
end
end
end
When I tried using the console, item.deal.price works just fine but not item.price.
In the line_item model, I tried attr_accessible :price but it did fix anything.
I checked my code vs the book and I can't tell any significant difference at all.
One idea is to set a database field for price for LineItems but the book doesn't do that and it violates the DRY principle.
Any help would be greatly appreciated as I've stared at the source code for hours and can't find anything wrong. Thanks.
You were distracted during reading the book. LineItem model does contain the price field. This totally complies with DRY principle, as there is a possibility of changing a price of a Product in the future and LineItem model shows as a history of deals.

Resources