• @moliliang 我觉得对于你的问题来说,你的解决方法很新颖,而且很简洁,需要赞一个!

  • @Qcoder 没注意已经这么多讨论了,画蛇添足了。。。

  • @Qcoder 到底是不是bug还是有争议的。因为实际上你的代码是可以动的。 参考你给的连接尝试了一下,下面的测试是通过的

    分析

    最后的测试里面, assert_equal Bicycle.name, price.priceable.class.name 是重点。 price.priceable_type 确实是 Car ,但这只是从Price model方向去找priceable的时候的问题, 而实际上创建price.priceable这个对象的时候,到底是Car还是Bicycle,看的是cars这个表里的type字段的值。

    结论

    • 对于你的Bicycle级连拿prices的时候,不定义方法应该也是正常能够跑的
    • Price去找priceable的纪录的时候,应该用Car还是实际的Bicycle,这个属于Rails的设计问题,个人觉得可以选择性的忽略 😅
    require 'active_record'
    require 'minitest/autorun'
    
    ActiveRecord::Base.establish_connection adapter: 'sqlite3', database: ':memory:'
    
    ActiveRecord::Base.connection.instance_eval do
      create_table(:cars) do |t|
        t.string :name
        t.string :type
        t.string :bicycle_column1
        t.integer :prices_count
      end
    
      create_table(:prices) do |t|
        t.string :name
        t.string :priceable_type
        t.integer :priceable_id
      end
    end
    
    class Car < ActiveRecord::Base
       has_many :prices, :as => :priceable, :dependent => :destroy
    end
    
    class Bicycle < Car
      def aaa?
        bicycle_column1 == 'aaa'
      end
    end
    
    class Price < ActiveRecord::Base
      belongs_to :priceable, :polymorphic => true, :counter_cache => true
    end
    
    class MyTest < Minitest::Test
      def test_1
        bicycle1 = Bicycle.create name: 'bircycle1', bicycle_column1: 'aaa'
        bicycle1.prices.create name: 'price1'
    
        price = Bicycle.first.prices.first
    
        assert_equal Bicycle.name, price.priceable.class.name
        assert_equal true, price.priceable.aaa?
        assert_equal bicycle1.prices.first, Price.first
      end
    end
    
  • @hfpp2012 嗯,也对。 如果这个定制只是针对一个项目的话,基本上 col-sm-10 之类的应该都是类似的,确实不需要 simple_form 之类的了。 👍

  • 先赞一个!!!

    其次,上面的代码里面的required,直接用new_record?的返回值就好了

    <%= f.image_file_field :image, required: @product.new_record?, class: 'form-control' %>
    

    第三是个疑问:自定义了这些方法之后,实际上在项目里面不同的页面上的布局还是不一样的。那样的话就需要把布局那部分的col-sm-10分离到方法的参数里面,而这样的情况应该还会有很多。那如果我们在项目中不断的增加需要的参数之后,最终的结果会不会还是变成了 simple_form 或者bootstrap_form这样的东西呢?

  • @bindiry 1楼的回答是正确的方法。 如果你想定义类方法,把你的方法定义在ClassMethods这个module里面就可以了。

    module Writable
      extend ActiveSupport::Concern
    
      included do
        attr_reader :write_worker
      end
    
      module ClassMethods
        def set_options(worker)
          @worker = worker
        end
      end
    end
    
    
  • 火速入手!

  • @modacker 或许和你的需求有点出入,如果你有多个App需要管理I18n的话,可以尝试一下这个, thoughtbot 出品的。 http://railscasts.com/episodes/336-copycopter?language=en&view=asciicast

  • 补充几个踩过的坑

    • 定义enum时自动增加的各个值对应的?!方法是model范围内有效的。如果不同的字段有同名的值的时候一定要注意
    # user.rb
      enum status: [:temporary, :active, :deleted]
      enum admin_status: [:active, :super_admin]
    
    # rails console
    irb(main):001:0> u = User.neww
    ArgumentError: You tried to define an enum named "admin_status" on the model "User", but this will generate a instance method "active?", which is already defined by another enum.
    ...
    
    • 修改以前定义好的enum时需要注意历史数据
    # 原来是这样的定义
    enum status: [:temporary, :active, :deleted]
    # 修改后,
    enum status: [:temporary, :active, :waiting, :deleted]
    # 如果这样修改的话,以前的`deleted`的数据修改后就变成`:waiting`了!!! :sleepy: 
    

    所以,不推荐使用[:temporary, :active, :deleted]的方式,尽量使用{ temporary: 1, active: 2, deleted: 3]这样的明确定义数值的方式

    • 自动增加的status=方法,参数是不允许的值的时候会抛出ArgumentError。在直接从网页上接收status的值的场景下一定要注意。 这种情况只有在运行的时候才会报错所以异常危险!!!
    irb(main):004:0> u1.status = 'aaa'
    ArgumentError: 'aaa' is not a valid status
        from /Users/blueplanet/sandbox/enum_test/vendor/bundle/ruby/2.3.0/gems/activerecord-4.2.5/lib/active_record/enum.rb:104:in `block (3 levels) in enum'
        from (irb):4
    
    • 由于会自动增加scope,所以要注意不要覆盖掉Rails默认的scope。比如enum status: { none: 0, active: 1, deleted: 2}就会覆盖掉Rails4增加的nonescope了。
  • 必须买!也希望是电子版!