Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/62.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails Rails/Ruby、混合模块和保持干燥_Ruby On Rails_Ruby - Fatal编程技术网

Ruby on rails Rails/Ruby、混合模块和保持干燥

Ruby on rails Rails/Ruby、混合模块和保持干燥,ruby-on-rails,ruby,Ruby On Rails,Ruby,我正在尝试为我的rails应用程序编写更多的模块化代码,因此我开始更多地在类中包含模块。我对它们的功能有基本的了解,但我发现在保持干燥的同时很难保持它们的灵活性 下面是一个最新的例子 我有一个叫做可接触的模块。它有两个非常基本的功能 确保数据库中存在正确的联系人列 验证某些字段 给你 module Contactable extend ActiveSupport::Concern ERROR = 'please ensure necessary fields are in place'

我正在尝试为我的rails应用程序编写更多的模块化代码,因此我开始更多地在类中包含模块。我对它们的功能有基本的了解,但我发现在保持干燥的同时很难保持它们的灵活性

下面是一个最新的例子

我有一个叫做可接触的模块。它有两个非常基本的功能

  • 确保数据库中存在正确的联系人列
  • 验证某些字段 给你

    module Contactable
      extend ActiveSupport::Concern
      ERROR = 'please ensure necessary fields are in place'
    
      included do
        REQUIRED_DATABASE_FIELDS.map { |rdf| raise "#{rdf} not included. #{ERROR}" unless column_names.include?(rdf)}
        REQUIRED_INPUT_FIELDS.map { |rif| validates rif.to_sym, presence: true}
      end
    end
    
    我希望contactable由其他三个模块(电话、电子邮件和地址)组成,其中包含需要的列数组和需要验证的字段。我现在正在研究的一个是“可寻址”

    module Addressable 
      extend ActiveSupport::Concern
      ERROR = 'please ensure necessary fields are in place'
    
      REQUIRED_DATABASE_FIELDS = %w{address1 
                                    address2 
                                    address3 
                                    town 
                                    county 
                                    country 
                                    postcode}
    
      REQUIRED_INPUT_FIELDS = %w{address1 postcode}
    
      included do
        REQUIRED_DATABASE_FIELDS.map { |rdf| raise "#{rdf} not included. #{ERROR}" unless column_names.include?(rdf)}
        REQUIRED_INPUT_FIELDS.map { |rif| validates rif.to_sym, presence: true}
      end
    end
    

    显然这里有重复。但是,如果我将此模块包括在contactable中,我就不需要重复,但这意味着contactable将始终包括Phoneable和Emailable。在某些情况下,我可能不想验证或要求这些特性。有什么方法可以实现这种灵活性吗?

    您应该在这里使用单元测试。通过检查模型(或它们包含的模块)中的数据库模式,您并没有真正实现任何目标。如果列不存在,应用程序将抛出NoMethodError或数据库驱动程序错误

    最好是实际进行单元测试,以覆盖您的模型并确保它们按预期工作

    require 'rails_helper'
    
    describe User
      # Tests the presence of the database column indirectly. 
      it { should respond_to :email }
    
      # Explicit test - there a very few good reasons to actually do this.
      it "should have the email column" do
        expect(User.column_names).to have_key :email 
      end
    end
    
    如果您使用的是RSpec,那么您可以使用共享示例来减少规范中的重复量

    # support/example_groups/addressable.rb
    require 'spec_helper'
    RSpec.shared_examples_for "an addressable" do
      it { should respond_to :address1 }
      it { should respond_to :address2 }
      it { should respond_to :address3 } 
      it { should respond_to :county } 
      it { should respond_to :postcode } 
      # ...
    end
    


    有关如何使用测试单元/minitest实现相同功能的示例,请参见。

    您可以执行以下操作:

    添加/app/models/concerns/fields_validator.rb

    添加/app/models/concerns/contact.rb

    添加/app/models/concerns/address.rb

    在模型中

    class Promotion < ActiveRecord::Base
      include Address
      include Contact
    
      validate_required_attributes
    end
    
    要检查这是否有效

    Promotion.new.save!
    "ActiveRecord::RecordInvalid: Validation failed: Sku can't be blank, Amount can't be blank, Observations can't be blank, Product details can't be blank, Offer details can't be blank"
    
    注意事项:

    • 将模块保留在自定义命名空间中。现有的
      可寻址
      模块将出现问题。例如:

      module MyApp
        module Addressable
        # code...
        end
      end
      
      class Promotion < ActiveRecord::Base
        include MyApp::Addressable
      
        validate_required_attributes
      end
      
      模块MyApp
      模块可寻址
      #代码。。。
      结束
      结束
      类升级
    • 您需要首先加载所有属性,然后应用验证。如果不这样做,如果模块共享属性,则可以重复验证

    • 共享逻辑进入
      字段验证模块

    首先考虑的问题是,您能否解释一下我可能会遇到哪些问题以及如何解决?如果我能给这更多的分数,我会的。我已经更新了我的答案。例如,您只需要将模块包装到另一个模块(
    MyApp
    )中。然后,需要使用名称空间包含模块。您可以使用
    包含MyApp::Addressable
    来代替
    包含Address
    module Address
      extend ActiveSupport::Concern
      include FieldsValidator
    
      included do
        puts "include address..."
        load_required_attributes(:sku, :amount, :observations)
      end
    end
    
    class Promotion < ActiveRecord::Base
      include Address
      include Contact
    
      validate_required_attributes
    end
    
    include address...
    loading attrs: [:sku, :amount, :observations]
    include contact...
    loading attrs: [:product_details, :observations, :offer_details]
    adds validation for sku
    adds validation for amount
    adds validation for observations
    adds validation for product_details
    adds validation for offer_details
    
    Promotion.new.save!
    "ActiveRecord::RecordInvalid: Validation failed: Sku can't be blank, Amount can't be blank, Observations can't be blank, Product details can't be blank, Offer details can't be blank"
    
    module MyApp
      module Addressable
      # code...
      end
    end
    
    class Promotion < ActiveRecord::Base
      include MyApp::Addressable
    
      validate_required_attributes
    end