Calling super in overriden scope defined in concern - ruby-on-rails-4

I'm looking to chain an additional query onto a scope in a model. The scope is defined in a concern.
module Companyable
extend ActiveSupport::Concern
included do
scope :for_company, ->(id) {
where(:company_id => id)
}
end
end
class Order < ActiveRecord::Base
include Companyable
# I'd like to be able to do something like this:
scope :for_company, ->(id) {
super(id).where.not(:status => 'cancelled')
}
end
However, that understandably throws a NameError: undefined method 'for_company' for class 'Order'

Here's the solution I came up with in my case:
Rather than scope, just go with a regular class method since scope is just "syntactic sugar" for a class method. This is easier to deal with when you need to override using super. In your case it would look like this:
module Companyable
extend ActiveSupport::Concern
module ClassMethods
def for_company(id)
where(:company_id => id)
end
end
end
class Order < ActiveRecord::Base
include Companyable
def self.for_company(id)
super(id).where.not(:status => 'cancelled')
end
end

Related

Accessing methods from module in resque job

Hi I have to access a method from a module in a resuq job, I keep getting this error: method not accessible. Am I using the module incorrectly??
class TestResqueJob
include TestModule
#queue = :test_resque
def self.perform(params)
method_from_module
end
end
module TestModule
def method_from_module
puts "test"
end
end
It seems that you are trying to call an instance method inside a public method. I f you want your module methods to be class methods change include to extend
class TestResqueJob
extend TestModule
#queue = :test_resque
def self.perform(params)
method_from_module
end
end
this will make all the methods you have defined in the module as class methods

How to structure namespaced modules

I am having trouble with Ruby class (constant) lookup within the context of a Rails engine gem.
I have a gem MyGem that is a Rails engine. It defines non-namespaced models that are expected to be overridden by the MainApp that would include the gem and namespaced modules, which are included in gem's and main_app's models to have a DRY way of defining reusable code.
Here is a sample code structure:
Two models
# in /app/models/user.rb
class User < ActiveRecord::Base
include MyGem::User::CommonExt
end
# in /app/models/comment.rb
class Comment < ActiveRecord::Base
include MyGem::Comment::CommonExt
end
Their two modules
# in /app/models/concerns/my_gem/user/common_ext.rb
module MyGem::User::CommonExt
def load_comment(id)
return Comment.find(id)
end
end
# in /app/models/concerns/my_gem/comment/common_ext.rb
module MyGem::Comment::CommonExt
def load_user(id)
return User.find(id)
end
end
Now, if I call
User.new.load_comment(1)
I get undefined method #find for MyGem::Comment::Module
I think I understand why this is happening - in the context of #load_comment definition, which is namespaced under MyGem, Comment constant lookup returns MyGem::Comment, rather than the more distant ::Comment
I would prefer not to have to prepend every model instance with ::.
Is there a file structure, model/class definition or configuration change I could use to make a call to Comment return the model Comment, not the MyGem::Comment module?
I would use inheritance instead of mixin in this case.
So in your gem/engine you could define your common class similar to this:
module MyGem
module Common
class Base < ActiveRecord::Base
# common functionality goes here
def load(record_type, id)
record_type.find(id)
end
end
end
end
Then in your main_app code:
class User < MyGem::Common::Base
...
end
Now you could do this:
User.new.load(Comment, 1)
This violates the Law of Demeter but hopefully it illustrates the point.
Doing it like this is DRY and has the added benefit that it prevents your gem from having to know about classes which are outside it's own scope.

How could I share scope method with other models using Rails 4 and mongoind

How could I share scope method with other models using Rails 4 and mongoind
if put scope in included do, the error was
NoMethodError: undefined method `scope' for User:Class
if put scope in module ClassMethods, the error was
NoMethodError: undefined method `scope' for RecentlySearch::ClassMethods:Module
Code snippet
class User
include RecentlySearch
include Mongoid::Document
field :history, type: Array
end
snippert 2
module RecentlySearch
extend ActiveSupport::Concern
module ClassMethods
scope :hi, -> {p 'hi'}
end
included do
scope :hi, -> {p 'hi'}
end
end
The scope class method comes from Mongoid::Document so when you:
include RecentlySearch
there is no scope method yet. You need to include Mongoid::Document first:
include Mongoid::Document
include RecentlySearch

Adding has_and_belong_to_many entity using static method

I have two models :
class Candidate < ActiveRecord::Base
has_and_belongs_to_many :skills
end
class Skill < ActiveRecord::Base
has_and_belongs_to_many :candidates
def self.add
find_or_create_by(name:"management")
end
end
The following execution seems to work fine :
>current_candidate.skills.count
=> 0
>current_candidate.skills.find_or_create_by(name:"mathematics")
=> ...
>current_candidate.skills.count
=> 1
But here is what happen when I use the static method add :
>current_candidate.skills.count
=> 0
>current_candidate.skills.add
=> ...
>current_candidate.skills.count
=> 0
The skill management is created, but not binded to my candidate entity.
I don't understand why the static method doesn't consider the current_candidate.
PS: It works well with direct binding (like has_many and belongs_to)
New answer (previous answer deleted):
Your code will not work because you have defined add as a class method of Skill. The class Skill has no relation to candidates. An instance of a Skill does have a relation to candidates.
So to fix this, I think it makes more sense to add an add_skill method on Candidate and remove the one in Skill.
class Candidate < ActiveRecord::Base
has_and_belongs_to_many :skills
def add_skill(skill_name)
skills.find_or_create_by(name: skill_name)
end
end
Usage:
current_candidate.add_skill('a_skill')
As stated in my previous answer, you might want to replace the find_or_create_by call with the bang version find_or_create_by! to catch (validation) errors.

Rails 4 concern errors

I've notice the new features of concern in rails4, and I read the document of it in http://edgeapi.rubyonrails.org/classes/ActiveSupport/Concern.html.
But it seems doesn't work as I expect. Here is my code of my /models/concerns/current_user.rb.
require 'active_support/concern'
module CurrentUser
extend ActiveSupport::Concern
module ClassMethods
def accessor_current_user
attr_accessor :current_user
end
end
end
class ActiveRecord::Base
include CurrentUser
end
You probably notice that last 3 lines of my code, that's because I want all my models can call the method and I think it may be a good way to achieve that. But when i start rails server, it just cannot call the accessor_current_user method. So I am confusing about this. I really don't know the reason. Hope someone can help me. :)
Update!
Finally, i found it's maybe a good way to create a ActiveRecord::Base class in the initializers fold, and then include the CurrentUser in the class.
Try:
require 'active_support/concern'
module CurrentUser
extend ActiveSupport::Concern
included do
attr_accessor :current_user
end
module ClassMethods
end
end
class ActiveRecord::Base
include CurrentUser
end
Then you should be able to do something like this:
foo = Foo.new
foo.current_user
Where Foo is:
class Foo < ActiveRecord:Base
include CurrentUser
end
The way you are calling accessor_current_user is wrong. This way you can call ActiveRecord::Base.accessor_current_user method and it will execute the code without any error. And then you can call
ar = ActiveRecord::Base.new
ar.current_user = "foo"
ar.current_user # this will return 'foo'
But the correct way to implement the attr_accessor using ActiveSupport::Concern is
module CurrentUser
extend ActiveSupport::Concern
included do
attr_accessor :current_user
end
end
If you are writing your code in rails, then you don't need require 'active_support/concern'. Please refer http://blog.neerajk.com/articles/2014-11-26-is-active-support-concern-really-another-concern/