0

すべてのモデルに 4 つの共通関数があります。

#Returns TRUE or FALSE depending on whether the column could be null or not
def self.null?(column)
  columns_hash[column].null
end

#Custom delete function to change a state (deleted is a field)
def custom_delete
  deleted = true
  save
end

def str_created_at(format = "%d/%m/%Y %I:%M %p")
  return created_at.in_time_zone.strftime(format)
end

def str_updated_at(format = "%d/%m/%Y %I:%M %p")
  return updated_at.in_time_zone.strftime(format)
end

これらの 4 つの関数 (そのうちの 1 つは抽象的です: null?) を単一のモジュールに移動しようとしましたが、うまくいきませんでした:

#config/application.rb
config.autoload_paths += Dir["#{config.root}/lib/**/"]

#app/models/post.rb
class Post < ActiveRecord::Base
    include BaseModel
    default_scope where(:deleted => false)
end

#lib/base_model.rb
module BaseModel

    def self.included(base)
        base.extend ClassMethods
    end

    module InstanceMethods

        def custom_delete
            deleted = true
            save
        end

        def str_created_at(format = "%d/%m/%Y %I:%M %p")
            return created_at.in_time_zone.strftime(format)
        end

        def str_updated_at(format = "%d/%m/%Y %I:%M %p")
            return updated_at.in_time_zone.strftime(format)
        end
    end 

    module ClassMethods
        include BaseModel::InstanceMethods

        def self.null?(column)
            columns_hash[column].null
        end
    end

end

Rails コンソールで:

> Post.null?("title")
> NoMethodError: undefined method 'null?' for #<Class:0x3f075c0>
> post = Post.first
> post.str_created_at
> NoMethodError: undefined method 'str_created_at' for #<Post:0x2975190>

これらの機能を正常に動作させる方法はありますか? 私はこのコードをStackoverflowで見つけましたが、少なくともRails3では機能していないようです

これらの関数を 1 行だけで追加できるようにしたいと思います: include BaseModel

そのため、他のモデルにも追加できます。

4

1 に答える 1

2

Concerns are the solution. It's really important to be able to modularize your application, both for rails apps that for libraries. Note that this approach can be pretty cool also when hanging with Engines.

Concerns must be placed in the concern folder, both for models and controllers. Just be careful to not use them too much. You must use it mainly when you share functionalities between your classes and when you want to make your model skinny. In the last case wait for it to be really big, otherwise concerns will become a trash directory and you'll lose its effect.

Configure application.rb

Here you can see how to organize your model and controller concerns.

module YourApp
  class Application < Rails::Application
    config.autoload_paths += %W(
      #{config.root}/app/controllers/concerns
      #{config.root}/app/models/concerns
    )
  end
end

Creating concerns

You can define your concern using ActiveSupport::Concern class. It simplify the 'including' phase (you you do not have to use base as prefix) and it automatically load the class methods that are inside of module ClassMethod.

Here an example of what change.

class Message < ActiveRecord::Base
  include Trashable
end

module Trashable
  extend ActiveSupport::Concern

  included do
    field :new
  end

  module ClassMethods
    # some class methods
  end

  # some instance methods
  end

Here you can find a nice article that explain them much more in details.

于 2012-08-23T20:57:16.510 に答える