代码之家  ›  专栏  ›  技术社区  ›  Xavier Shay

使用多个关系时的rom rb表单验证

  •  0
  • Xavier Shay  · 技术社区  · 9 年前

    我正在尝试 http://rom-rb.org/ 并且无法确定如何在存在多个源模型的情况下通过状态验证。我希望下面的脚本可以保存一个新的活动和组织者,但它说 event_name 不存在。

    我错过了什么?

    require 'bundler/inline'
    
    gemfile do
      source 'https://rubygems.org'
      gem 'rom'
      gem 'rom-sql'
      gem 'rom-rails'
      gem 'activemodel'
      gem 'sqlite3'
      gem 'activesupport'
    end
    
    require 'rom'
    require 'rom-rails'
    
    `rm -Rf /tmp/romtest.sqlite`
    ROM.setup(:sql, 'sqlite:///tmp/romtest.sqlite')
    
    class Events < ROM::Relation[:sql]
    end
    
    class Organisers < ROM::Relation[:sql]
    end
    
    class CreateEvent < ROM::Commands::Create[:sql]
      relation :events
      register_as :create
      result :one
    
      associates :organiser, key: [:organiser_id, :id]
    end
    
    class CreateOrganiser < ROM::Commands::Create[:sql]
      relation :organisers
      register_as :create
      result :one
    end
    
    class CreateEventWithOrganiser < ROM::Model::Form
      commands organisers: :create, events: :create
    
      input do
        attribute :email
        attribute :event_name
      end
    
      validations do
        validates :event_name, presence: true
      end
    
      def commit!
        command = organisers.create.with(
          email: email,
        ) >> events.create.with(
          name: event_name,
        )
    
        command.transaction do
          command.call
        end
      end
    end
    
    ROM.finalize
    rom = ROM.env
    gateway = rom.gateways.fetch(:default)
    migration = gateway.migration do
      change do
        create_table :organisers do
          primary_key :id
          column :email, String, null: false
        end
    
        create_table :events do
          primary_key :id
          column :name, String, null: false
          column :organiser_id, Integer, null: false
        end
      end
    end
    
    migration.apply(gateway.connection, :up)
    
    f = CreateEventWithOrganiser.build(
      email:      'test@example.com',
      event_name: 'Test Event'
    )
    
    # Unexpectedly fails
    f.save
    puts f.errors.full_messages
    # => "Event name can't be blank"
    
    1 回复  |  直到 9 年前
        1
  •  2
  •   solnic    9 年前

    这是您的脚本的更新版本,它可以工作:

    require 'rom'
    require 'rom-rails'
    
    `rm -Rf /tmp/romtest.sqlite`
    ROM.setup(:sql, 'sqlite:///tmp/romtest.sqlite')
    
    class Events < ROM::Relation[:sql]
    end
    
    class Organisers < ROM::Relation[:sql]
    end
    
    class CreateEvent < ROM::Commands::Create[:sql]
      relation :events
      register_as :create
      result :one
    
      associates :organiser, key: [:organiser_id, :id]
    end
    
    class CreateOrganiser < ROM::Commands::Create[:sql]
      relation :organisers
      register_as :create
      result :one
    end
    
    class CreateEventWithOrganiser < ROM::Model::Form
      inject_commands_for :organisers, :events
    
      input do
        attribute :email
        attribute :event_name
      end
    
      validations do
        validates :event_name, presence: true
      end
    
      def commit!
        validate!
    
        return if errors.any?
    
        command = organisers.create.with(
          email: email
        ) >> events.create.with(
          name: event_name
        )
    
        command.transaction do
          command.call
        end
      end
    end
    
    ROM.finalize
    rom = ROM.env
    gateway = rom.gateways.fetch(:default)
    migration = gateway.migration do
      change do
        create_table :organisers do
          primary_key :id
          column :email, String, null: false
        end
    
        create_table :events do
          primary_key :id
          column :name, String, null: false
          column :organiser_id, Integer, null: false
        end
      end
    end
    
    migration.apply(gateway.connection, :up)
    
    f = CreateEventWithOrganiser.build(
      email:      'test@example.com',
      event_name: 'Test Event'
    )
    
    puts f.save.result.inspect
    # #<ROM::Commands::Result::Success:0x007fa92b589ea0 @value={:id=>1, :name=>"Test Event", :organiser_id=>1}>
    

    它不起作用的原因 commands 这是因为此方法将为表单生成命令对象,并为每个命令设置提供的验证,只有在使用单个命令时才能正常工作。否则,每个命令都使用相同的验证器,这是不合理的。当您使用 inject_commands_for 它将在没有设置验证器的地方抓取您自己的命令,这样您就可以自己处理验证。

    我认为我们应该停止在命令上设置验证器,这会使您的原始示例工作,但请注意,您需要调用 validate! 你自己

    我希望这有帮助。

    我还创建了一个要点,展示了如何在没有表单的情况下执行相同操作: https://gist.github.com/solnic/3b68342482cf1414f719