-
-
Save dhh/1014971 to your computer and use it in GitHub Desktop.
# autoload concerns | |
module YourApp | |
class Application < Rails::Application | |
config.autoload_paths += %W( | |
#{config.root}/app/controllers/concerns | |
#{config.root}/app/models/concerns | |
) | |
end | |
end | |
# app/models/concerns/trashable.rb | |
module Trashable | |
extend ActiveSupport::Concern | |
included do | |
default_scope where(trashed: false) | |
scope :trashed, where(trashed: true) | |
end | |
def trash | |
update_attribute :trashed, true | |
end | |
end | |
# app/models/message.rb | |
class Message < ActiveRecord::Base | |
include Trashable, Subscribable, Commentable, Eventable | |
end |
@dhh I don't think this works from the scoping standpoint:
Message.scoped.to_sql => "SELECT messages
.* FROM messages
WHERE messages
.trashed
= 0" # which is expected
but:
Message.trashed.to_sql => "SELECT messages
.* FROM messages
WHERE messages
.trashed
= 0 AND messages
.trashed
= 1" # which returns nothing b/c a message cannot be both T and F
Would you have to unscope from the default_scope in the trashed scope to get the expected behavior?
(Note: Rails 3.0.7)
Just FYI, having a similar conversation here: https://gist.github.com/979005#comments
Proposed solution: https://gist.github.com/1114452 <= thoughts? Thanks to @webficient for their input on it
I was wondering if is there any way to disable default_scope for a belongs_to relation, so I was trying to do that, overriding the getter method for the association, I've put all those things in a module.
# lib/unscopable.rb
module Unscopable
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def unscopable(*args, &block)
args.each do |name|
define_unscoped_method name
alias_method_chain name, :unscoped
end
end
def define_unscoped_method(name)
name = name.to_s
model = name.classify
attribute = "#{name}_id"
method_name = "#{name}_with_unscoped"
define_method(method_name) do
object = Object.const_get(model)
object.unscoped { object.find eval(attribute) }
end
end
end
end
And for example we could disable the default scope in this way
# app/models/author.rb
class Author < ActiveRecord::Base
include Unscopable
belongs_to message
unscopable :message
end
I don't really like the name 'unscopable' :-), I've used it just for this example.
what do you think?
Instead of the autoload paths:
#{config.root}/app/controllers/concerns
#{config.root}/app/models/concerns
Does anybody have any reasons (stylistic or practical) as to why not use
# app/models/concerns/trashable.rb
module Concerns::Trashable
Maybe it looks better than having to repeat the module for each concern?
include Concerns::Trashable, Concerns::Subscribable, Concerns::Commentable, Concerns::Eventable
I think the given that Rails4 will have those paths autoloaded, it makes more sense to not namespace those paths, and thus not use Concerns::.
@justin808
I think you can create a folder called shared
for all shared modules
So that you have to include Shared::Trashable
in app/models/concerns/shared/trashable.rb
, not just Trashable
Also if you got both Message::Trashable
and Shared::Trashable
, you won't be confused on which to include
I recently saw this article as a counterpoint to this approach to breaking down model classes:
http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/
Great, I also found few more ways to keep your code modular - http://amolnpujari.wordpress.com/2013/04/09/184/
concerns sucks compared to DCI. I hope ruby community will improve ruby to support DCI (extend/unextend modules on instances). Roles >>> concerns. Because roles are limited to contexts and you can't write spaghetti code, when you use method from role that should not be involved in current context. It is clear signal to developer - that something went wrong, architecture should be improved. In case of concerns you put everything in one object and let mess and spaghetti code happen in contexts (in Rails case in controllers or other "services" modules used by controllers).
@IZBOR besides the fact that this discussion has nothing to do with DCI, DCI is slow and is not really spreading a ton because of that.
Great article from codeclimate on making fat model thin http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/
clear and clean !