I am currently trying to implement activity_notification gem. The issue I am having, is the gem is searching for the user_id, but I have implemented friendly_id and the gem is unable to find the user. The parameters show {"target_type"=>"users", "devise_type"=>"users", "user_id"=>"dannytom222"} and then the gem fails with Couldn't find User. I'm using the predefined controller for the gem, and cannot locate the method that is throwing this error.
In my stack trace, it shows
def find_by!(*args) # :nodoc:
find_by(*args) || raise(RecordNotFound.new("Couldn't find #{name}", name))
end
Full trace
activerecord (5.1.5) lib/active_record/core.rb:228:in `find_by!'
activity_notification (1.4.4) lib/activity_notification/controllers/common_controller.rb:28:in `set_target'
activesupport (5.1.5) lib/active_support/callbacks.rb:413:in `block in make_lambda'
activesupport (5.1.5) lib/active_support/callbacks.rb:197:in `block (2 levels) in halting'
actionpack (5.1.5) lib/abstract_controller/callbacks.rb:12:in `block (2 levels) in <module:Callbacks>'
activesupport (5.1.5) lib/active_support/callbacks.rb:198:in `block in halting'
friendly_id for user.rb
extend FriendlyId
friendly_id :username, use: :slugged
migration file for friendly_id slug
class AddSlugToUsers < ActiveRecord::Migration[5.1]
def change
add_column :users, :slug, :string
add_index :users, :slug, unique: true
end
end
How can I get activity_notification to accept the username attribute, in place of the user_id?
UPDATE:
I changed the link_to method to
<%= link_to 'Notifications' user_notifications_path(current_user.id) %> and it works.
You probably have to user user.friendly_id or however, you have declared it to your model instead of user.id. This seems to the issue
Related
I am programming a small rails api for practice. The goal is to POST some data and then save it (after further processing) in a database. The object is being created successfuly. On the save method appears an error which I cannot explain:
NoMethodError (undefined method `[]' for nil:NilClass): app/controllers/api/v1/calculations_controller.rb:19:in `create'
It appears in the :create method (on POST):
# POST /calculations
def create
#calculation = Calculation.new(calculation_params)
if #calculation.save # <- This is line 19
render json: #calculation, status: :created, location: #calculation
else
render json: #calculation.errors, status: :unprocessable_entity
end
end
The model looks like this:
require 'digest'
class Calculation < ApplicationRecord
attr_reader :value, :hash_value, :algorithm, :timestamp
##known_algorithms = ['SHA2_256', 'SHA2_384', 'SHA2_512']
def initialize (params)
#value = params[:value]
#algorithm = params[:algorithm]
validate!
#hash_value, #timestamp = digest
end
private
def digest
case #algorithm
when 'SHA2_256'
result = Digest::SHA2.hexdigest(#value)
when 'SHA2_384'
result = Digest::SHA2.new(384).hexdigest(#value)
when 'SHA2_512'
result = Digest::SHA2.new(512).hexdigest(#value)
end
return result, DateTime.now
end
def validate!
raise ArgumentError.new('Value cannot be empty or NIL!') if #value.nil? or #value.empty?
raise ArgumentError.new('Unknown hashing algorithm!') unless ##known_algorithms.include? #algorithm
end
end
Why does the NoMethodError appear? Did I override some important part in the model class?
Full stack trace as requested:
/home/pbz/.gem/ruby/2.5.0/gems/activerecord-5.2.2/lib/active_record/transactions.rb:424:in `clear_transaction_record_state'
/home/pbz/.gem/ruby/2.5.0/gems/activerecord-5.2.2/lib/active_record/transactions.rb:330:in `ensure in rollback_active_record_state!'
/home/pbz/.gem/ruby/2.5.0/gems/activerecord-5.2.2/lib/active_record/transactions.rb:330:in `rollback_active_record_state!'
/home/pbz/.gem/ruby/2.5.0/gems/activerecord-5.2.2/lib/active_record/transactions.rb:309:in `save'
/home/pbz/.gem/ruby/2.5.0/gems/activerecord-5.2.2/lib/active_record/suppressor.rb:44:in `save'
/home/pbz/RubymineProjects/hasher_api/app/controllers/api/v1/calculations_controller.rb:20:in `create'
/home/pbz/.gem/ruby/2.5.0/gems/actionpack-5.2.2/lib/action_controller/metal/basic_implicit_render.rb:6:in `send_action'
/home/pbz/.gem/ruby/2.5.0/gems/actionpack-5.2.2/lib/abstract_controller/base.rb:194:in `process_action'
/home/pbz/.gem/ruby/2.5.0/gems/actionpack-5.2.2/lib/action_controller/metal/rendering.rb:30:in `process_action'
/home/pbz/.gem/ruby/2.5.0/gems/actionpack-5.2.2/lib/abstract_controller/callbacks.rb:42:in `block in process_action'
/home/pbz/.gem/ruby/2.5.0/gems/activesupport-5.2.2/lib/active_support/callbacks.rb:132:in `run_callbacks'
/home/pbz/.gem/ruby/2.5.0/gems/actionpack-5.2.2/lib/abstract_controller/callbacks.rb:41:in `process_action'
/home/pbz/.gem/ruby/2.5.0/gems/actionpack-5.2.2/lib/action_controller/metal/rescue.rb:22:in `process_action'
/home/pbz/.gem/ruby/2.5.0/gems/actionpack-5.2.2/lib/action_controller/metal/instrumentation.rb:34:in `block in process_action'
/home/pbz/.gem/ruby/2.5.0/gems/activesupport-5.2.2/lib/active_support/notifications.rb:168:in `block in instrument'
/home/pbz/.gem/ruby/2.5.0/gems/activesupport-5.2.2/lib/active_support/notifications/instrumenter.rb:23:in `instrument'
/home/pbz/.gem/ruby/2.5.0/gems/activesupport-5.2.2/lib/active_support/notifications.rb:168:in `instrument'
/home/pbz/.gem/ruby/2.5.0/gems/actionpack-5.2.2/lib/action_controller/metal/instrumentation.rb:32:in `process_action'
/home/pbz/.gem/ruby/2.5.0/gems/actionpack-5.2.2/lib/action_controller/metal/params_wrapper.rb:256:in `process_action'
/home/pbz/.gem/ruby/2.5.0/gems/activerecord-5.2.2/lib/active_record/railties/controller_runtime.rb:24:in `process_action'
/home/pbz/.gem/ruby/2.5.0/gems/actionpack-5.2.2/lib/abstract_controller/base.rb:134:in `process'
/home/pbz/.gem/ruby/2.5.0/gems/actionpack-5.2.2/lib/action_controller/metal.rb:191:in `dispatch'
/home/pbz/.gem/ruby/2.5.0/gems/actionpack-5.2.2/lib/action_controller/metal.rb:252:in `dispatch'
/home/pbz/.gem/ruby/2.5.0/gems/actionpack-5.2.2/lib/action_dispatch/routing/route_set.rb:52:in `dispatch'
/home/pbz/.gem/ruby/2.5.0/gems/actionpack-5.2.2/lib/action_dispatch/routing/route_set.rb:34:in `serve'
/home/pbz/.gem/ruby/2.5.0/gems/actionpack-5.2.2/lib/action_dispatch/journey/router.rb:52:in `block in serve'
/home/pbz/.gem/ruby/2.5.0/gems/actionpack-5.2.2/lib/action_dispatch/journey/router.rb:35:in `each'
/home/pbz/.gem/ruby/2.5.0/gems/actionpack-5.2.2/lib/action_dispatch/journey/router.rb:35:in `serve'
/home/pbz/.gem/ruby/2.5.0/gems/actionpack-5.2.2/lib/action_dispatch/routing/route_set.rb:840:in `call'
/home/pbz/.gem/ruby/2.5.0/gems/rack-2.0.6/lib/rack/etag.rb:25:in `call'
/home/pbz/.gem/ruby/2.5.0/gems/rack-2.0.6/lib/rack/conditional_get.rb:38:in `call'
/home/pbz/.gem/ruby/2.5.0/gems/rack-2.0.6/lib/rack/head.rb:12:in `call'
/home/pbz/.gem/ruby/2.5.0/gems/activerecord-5.2.2/lib/active_record/migration.rb:559:in `call'
/home/pbz/.gem/ruby/2.5.0/gems/actionpack-5.2.2/lib/action_dispatch/middleware/callbacks.rb:28:in `block in call'
/home/pbz/.gem/ruby/2.5.0/gems/activesupport-5.2.2/lib/active_support/callbacks.rb:98:in `run_callbacks'
/home/pbz/.gem/ruby/2.5.0/gems/actionpack-5.2.2/lib/action_dispatch/middleware/callbacks.rb:26:in `call'
/home/pbz/.gem/ruby/2.5.0/gems/actionpack-5.2.2/lib/action_dispatch/middleware/executor.rb:14:in `call'
/home/pbz/.gem/ruby/2.5.0/gems/actionpack-5.2.2/lib/action_dispatch/middleware/debug_exceptions.rb:61:in `call'
/home/pbz/.gem/ruby/2.5.0/gems/actionpack-5.2.2/lib/action_dispatch/middleware/show_exceptions.rb:33:in `call'
/home/pbz/.gem/ruby/2.5.0/gems/railties-5.2.2/lib/rails/rack/logger.rb:38:in `call_app'
/home/pbz/.gem/ruby/2.5.0/gems/railties-5.2.2/lib/rails/rack/logger.rb:26:in `block in call'
/home/pbz/.gem/ruby/2.5.0/gems/activesupport-5.2.2/lib/active_support/tagged_logging.rb:71:in `block in tagged'
/home/pbz/.gem/ruby/2.5.0/gems/activesupport-5.2.2/lib/active_support/tagged_logging.rb:28:in `tagged'
/home/pbz/.gem/ruby/2.5.0/gems/activesupport-5.2.2/lib/active_support/tagged_logging.rb:71:in `tagged'
/home/pbz/.gem/ruby/2.5.0/gems/railties-5.2.2/lib/rails/rack/logger.rb:26:in `call'
/home/pbz/.gem/ruby/2.5.0/gems/actionpack-5.2.2/lib/action_dispatch/middleware/remote_ip.rb:81:in `call'
/home/pbz/.gem/ruby/2.5.0/gems/actionpack-5.2.2/lib/action_dispatch/middleware/request_id.rb:27:in `call'
/home/pbz/.gem/ruby/2.5.0/gems/rack-2.0.6/lib/rack/runtime.rb:22:in `call'
/home/pbz/.gem/ruby/2.5.0/gems/activesupport-5.2.2/lib/active_support/cache/strategy/local_cache_middleware.rb:29:in `call'
/home/pbz/.gem/ruby/2.5.0/gems/actionpack-5.2.2/lib/action_dispatch/middleware/executor.rb:14:in `call'
/home/pbz/.gem/ruby/2.5.0/gems/actionpack-5.2.2/lib/action_dispatch/middleware/static.rb:127:in `call'
/home/pbz/.gem/ruby/2.5.0/gems/rack-2.0.6/lib/rack/sendfile.rb:111:in `call'
/home/pbz/.gem/ruby/2.5.0/gems/railties-5.2.2/lib/rails/engine.rb:524:in `call'
/home/pbz/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/puma-3.12.0/lib/puma/configuration.rb:225:in `call'
/home/pbz/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/puma-3.12.0/lib/puma/server.rb:658:in `handle_request'
/home/pbz/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/puma-3.12.0/lib/puma/server.rb:472:in `process_client'
/home/pbz/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/puma-3.12.0/lib/puma/server.rb:332:in `block in run'
/home/pbz/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/puma-3.12.0/lib/puma/thread_pool.rb:133:in `block in spawn_thread'
Don't override initialize in the AR. It could possibly break a lot of stuff in your models.
You can use after_initialize.
The after_initialize callback will be called whenever an Active Record
object is instantiated, either by directly using new or when a record
is loaded from the database. It can be useful to avoid the need to
directly override your Active Record initialize method.
def after_initialize
# Gets called right after Calculation.new
# Do some stuff here
end
If you still want to use initialize you must do something like this:
def initialize(attributes = {})
super
self.attributes = attributes
end
I did find out (thanks to #Зелёный), that to create values for the model after creating it (new) I need to use the after_initialize callback Rails provides. Together with this comment on how to access model instance variables, I was able to achieve the functionality I wanted.
The original NoMethodError was a result of my incorrect use of the initialize method. The following code is the final result, which works with the default controller.
require 'digest'
class Calculation < ApplicationRecord
##known_algorithms = ['SHA2_256', 'SHA2_384', 'SHA2_512']
after_initialize :init
private
def init
validate!
calculate!
end
def calculate!
self.hash_value, self.timestamp = digest
end
def digest
case algorithm
when 'SHA2_256'
result = Digest::SHA2.hexdigest(value)
when 'SHA2_384'
result = Digest::SHA2.new(384).hexdigest(value)
when 'SHA2_512'
result = Digest::SHA2.new(512).hexdigest(value)
end
return result, DateTime.now
end
def validate!
raise ArgumentError.new('Value cannot be empty or NIL!') if value.nil? or value.empty?
raise ArgumentError.new('Unknown hashing algorithm!') unless ##known_algorithms.include? algorithm
end
end
I spend few hours trying to find solution of my problem, but lost any hope to understood what i am done wrong.
Rails 4.2.6
my model:
app/models/component.rb
class Component < ActiveRecord::Base
validates :name, presence: true,
uniqueness: true,
forbid_changing: true #TODO [VS] Fix custom validator autoload
validates :label, presence: true,
uniqueness: true
end
my validator:
class ForbidChangingValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
if record.send "#{attribute}_changed?".to_sym
record.errors[attribute] << options[:message] || t(:changing_forbidden)
end
end
end
when try reload the page i got error:
Unknown validator: 'ForbidChangingValidator'
ArgumentError - Unknown validator: 'ForbidChangingValidator':
activemodel (4.2.6) lib/active_model/validations/validates.rb:120:in `rescue in block in validates'
activemodel (4.2.6) lib/active_model/validations/validates.rb:117:in `block in validates'
activemodel (4.2.6) lib/active_model/validations/validates.rb:113:in `validates'
app/models/component.rb:6:in `<class:Component>'
app/models/component.rb:1:in `<top (required)>'
activesupport (4.2.6) lib/active_support/dependencies.rb:457:in `block in load_file'
activesupport (4.2.6) lib/active_support/dependencies.rb:647:in `new_constants_in'
activesupport (4.2.6) lib/active_support/dependencies.rb:456:in `load_file'
activesupport (4.2.6) lib/active_support/dependencies.rb:354:in `require_or_load'
activesupport (4.2.6) lib/active_support/dependencies.rb:494:in `load_missing_constant'
activesupport (4.2.6) lib/active_support/dependencies.rb:184:in `const_missing'
activesupport (4.2.6) lib/active_support/inflector/methods.rb:261:in `block in constantize'
activesupport (4.2.6) lib/active_support/inflector/methods.rb:259:in `constantize'
activesupport (4.2.6) lib/active_support/core_ext/string/inflections.rb:66:in `constantize'
repositor (0.6.0) lib/repositor/active_record.rb:6:in `initialize'
but when i am trying to call this validator from console i got:
!! #<ArgumentError: A copy of Component has been removed from the module tree but is still active!>
I found a lot of messages about thig issue, but can't to resolve mine.
Please, help somebody....
I found the issue. It's about naming policy. It strange ways rails try inflect the validator name.
I renamed my validator to ForbidChangesValidator and file also.
Everything goes great.
Thx all for attention.
Custom validations using using ActiveModel::EachValidator need to be declared in the root namespace or "core" autoload paths (however you want to define these directories).
For example:
(YES means will work and NO means won't work)
app/validations => YES since it is a new dir off of app/ it qualifies for root namespace
app/models => YES since it is a core directory
app/models/concerns => YES since it is a core directory
app/models/validations => NO Requires name spacing since it is a child directory off a core one.
Restarting the server fixed the issue for me, since everything else was right in place
Make sure you defined ForbidChangingValidator at app/validators/forbid_changing_validator.rb and add the configuration to:
config/application.rb
# add custom validators path
config.autoload_paths += %W["#{config.root}/app/validators/"]
I'm trying to make a contact form work by following this tutorial, but I keep having the error : uninitialized constant ApplicationMailer after i submit the form.
the traces give the following informations:
app/mailers/message_mailer.rb:1:in <top (required)>'
app/controllers/messages_controller.rb:9:in create'
actionpack (4.2.5) lib/action_controller/metal/implicit_render.rb:4:in send_action'
actionpack (4.2.5) lib/abstract_controller/base.rb:198:in process_action'
actionpack (4.2.5) lib/action_controller/metal/rendering.rb:10:in process_action'
actionpack (4.2.5) lib/abstract_controller/callbacks.rb:20:in block in process_action'
activesupport (4.2.5) lib/active_support/callbacks.rb:117:in call'
activesupport (4.2.5) lib/active_support/callbacks.rb:117:in call'
activesupport (4.2.5) lib/active_support/callbacks.rb:555:in block (2 levels) in compile'
activesupport (4.2.5) lib/active_support/callbacks.rb:505:in call'
activesupport (4.2.5) lib/active_support/callbacks.rb:505:in call'
activesupport (4.2.5) lib/active_support/callbacks.rb:92:in __run_callbacks__'
activesupport (4.2.5) lib/active_support/callbacks.rb:778:in _run_process_action_callbacks'`
Here are the file i have :
controllers/messages_controller.rb
class MessagesController < ApplicationController
def new
#message = Message.new
end
def create
#message = Message.new(message_params)
if #message.valid?
MessageMailer.message_me(#message).deliver_now
redirect_to new_message_path, notice: "Thankyou for your message."
else
render :new
end
end
private
def message_params
params.require(:message).permit(:name, :email, :subject, :content)
end
end
models/message.rb
class Message
include ActiveModel::Model
attr_accessor :name, :email, :subject, :content
validates :name, :email, :subject, :content, presence: true
end
mailers/message_mailer.rb
class MessageMailer < ApplicationMailer
default :to => "jd.levarato#gmail.com"
def message_me(msg)
#msg = msg
mail from: #msg.email, subject: #msg.subject, body: #msg.content
end
end
You have to create ApplicationMailer class that inherits from ActionMailer::Base.
application_mailer.rb
class ApplicationMailer < ActionMailer::Base
default from: 'from#exmaple.com'
layout 'mailer'
end
Or you can simply inherit ActionMailer::Base to your MessageMailer
class MessageMailer < ActionMailer::Base
default :to => "jd.levarato#gmail.com"
def message_me(msg)
#msg = msg
mail from: #msg.email, subject: #msg.subject, body: #msg.content
end
end
I'm building a Rails shopping cart app using Redis. Everything works fine until I try to view my cart, at which point I get this error.
NoMethodError in CartsController#show
undefined method `SMEMBERS' for nil:NilClass
Extracted source (around line #6):
5 def show
6 cart_ids = $redis.SMEMBERS current_user_cart
7 #order_items = current_order.order_items
8 end
The beginning of the full trace:
app/controllers/carts_controller.rb:6:in `show'
actionpack (4.2.0) lib/action_controller/metal/implicit_render.rb:4:in `send_action'
actionpack (4.2.0) lib/abstract_controller/base.rb:198:in `process_action'
actionpack (4.2.0) lib/action_controller/metal/rendering.rb:10:in `process_action'
actionpack (4.2.0) lib/abstract_controller/callbacks.rb:20:in `block in process_action'
activesupport (4.2.0) lib/active_support/callbacks.rb:117:in `call'
activesupport (4.2.0) lib/active_support/callbacks.rb:117:in `call'
activesupport (4.2.0) lib/active_support/callbacks.rb:169:in `block in halting'
activesupport (4.2.0) lib/active_support/callbacks.rb:234:in `call'
...and thence through a bunch more behind-the-scenes stuff I haven't touched, mostly activesupport, activerecord, and railties.
Redis-server is installed and responsive; I have tested it with redis-cli.
Config/initializers/redis.rb:
uri = URI.parse(ENV["REDISTOGO_URL"])
REDIS = Redis.new(:url => uri)
App/controllers/carts_controller.rb:
class CartsController < ApplicationController
before_action :authenticate_user!
def show
cart_ids = $redis.SMEMBERS current_user_cart
#order_items = current_order.order_items
end
def add
$redis.SADD current_user_cart, params[:product_id]
render json: current_user.cart_count, status: 200
end
def remove
$redis.SREM current_user_cart, params[:product_id]
render json: current_user.cart_count, status: 200
end
private
def current_user_cart
"cart#{current_user.id}"
end
end
The worst part is that I had this problem last week, fixed it, and neglected to write down what the fix was! Anybody have any leads?
You are using uninitialized global variable $redis (look at your initializers/redis.rb where you declared constant REDIS but not $redis)
Ruby is case-sensitive language, the SMEMBERS and smembers are two different methods. So, I think you should use smembers method.
Turned out I had two versions of redis installed. I don't know if that was causing the problem, but when I uninstalled both and reinstalled the gem, the problem disappeared!
I have two models as follows:
module FullcalendarEngine
class Event < ActiveRecord::Base
belongs_to :profile, polymorphic: :true
accepts_nested_attributes_for :profile
end
end
class UserProfile < ActiveRecord::Base
has_many :fullcalendar_engine_events, as: :profile, class_name: 'FullcalendarEngine::Event'
end
I can save this relation through the console:
l = UserProfile.first
e = l.fullcalendar_engine_events.build
e.save!
However, when I try it through a form submission, I get the following error:
NameError - uninitialized constant FullcalendarEngine::Event::Profile:
activerecord (4.1.5) lib/active_record/inheritance.rb:133:in `compute_type'
activerecord (4.1.5) lib/active_record/reflection.rb:221:in `klass'
activerecord (4.1.5) lib/active_record/nested_attributes.rb:545:in `raise_nested_attributes_record_not_found!'
activerecord (4.1.5) lib/active_record/nested_attributes.rb:387:in `assign_nested_attributes_for_one_to_one_association'
activerecord (4.1.5) lib/active_record/nested_attributes.rb:343:in `profile_attributes='
activerecord (4.1.5) lib/active_record/attribute_assignment.rb:45:in `public_send'
activerecord (4.1.5) lib/active_record/attribute_assignment.rb:45:in `_assign_attribute'
activerecord (4.1.5) lib/active_record/attribute_assignment.rb:56:in `block in assign_nested_parameter_attributes'
activerecord (4.1.5) lib/active_record/attribute_assignment.rb:56:in `each'
activerecord (4.1.5) lib/active_record/attribute_assignment.rb:56:in `assign_nested_parameter_attributes'
activerecord (4.1.5) lib/active_record/attribute_assignment.rb:36:in `assign_attributes'
activerecord (4.1.5) lib/active_record/core.rb:455:in `init_attributes'
activerecord (4.1.5) lib/active_record/core.rb:198:in `initialize'
activerecord (4.1.5) lib/active_record/inheritance.rb:30:in `new'
activerecord (4.1.5) lib/active_record/inheritance.rb:30:in `new'
This is the controller and form:
#profile = Profile.find(params[:profile])
#event = #profile.fullcalendar_engine_events.build
<%= form_for #event %>
<%= f.fields_for :profile, #profile do |builder| %>
<%= builder.hidden_field :id %>
<% end %>
<% end %>
What's submitted to server (I use ... to remove unncessary stuff):
Parameters: { ... "event"=>{ ... , "profile_attributes"=>{"id"=>"2"}}}
I've used polymorphic relations in the past with fields_for. So I am not sure what's going on here.
At the FullcalendarEngine::Event class, your belongs_to should be declared like this:
belongs_to :profile, polymorphic: :true, class_name: "::Profile"
The '::' forces the const lookup to happen from the root of the namespaces instead of inside the current namespace.