• ActiveRecord Store 使用介绍 at 2017年03月08日

    👍 ,的确很坑,得定义permissions= 的行为才行

  • ActiveRecord Store 使用介绍 at 2017年03月08日

    哦,这个用法没试过,回头试试。我想当然以为serialize要求数据库类型必须为string了

    不过搜了下5.0的doc,貌似不推荐这种情况用serialize了

    http://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/Serialization/ClassMethods.html

    If you have an attribute that needs to be saved to the database as an object, and retrieved as the same object, then specify the name of that attribute using this method and it will be handled automatically. The serialization is done through YAML. If class_name is specified, the serialized object must be of that class on assignment and retrieval. Otherwise SerializationTypeMismatch will be raised.

    Empty objects as {}, in the case of Hash, or [], in the case of Array, will always be persisted as null.

    Keep in mind that database adapters handle certain serialization tasks for you. For instance: json and jsonb types in PostgreSQL will be converted between JSON object/array syntax and Ruby Hash or Array objects transparently. There is no need to use serialize in this case.

    For more complex cases, such as conversion to or from your application domain objects, consider using the ActiveRecord::Attributes API.

  • ActiveRecord Store 使用介绍 at 2017年03月08日

    这个功能只要orm层可以反射为hash就可以实现了,使用hstore或者serialize在这个场景并没有啥区别,但是我的意思是hstore的好处是,它是pg原生支持的类型,可以做

    SELECT
     sum (attrs -> 'like_count') As total_likes
    FROM
     posts;
    GROUP BY xxx
    

    这种级别的操作,所以如果数据库层面原生支持json,最好直接用原生类型,而不是serialize。

  • ActiveRecord Store 使用介绍 at 2017年03月08日

    是不冲突,效率低功能少呀

  • ActiveRecord Store 使用介绍 at 2017年03月08日

    postgre 原生的数据类型支持索引,支持数据库级别的操作,能用原生就用原生的 active record 的方案是在数据库不支持的前提下没办法的方案。

  • 比如下面payment里面这段代码

    def self.create_from_orders! user, *orders
      orders.flatten!
    
      payment = nil
      transaction do
        payment = user.payments.create!(
          total_money: orders.sum(&:total_money)
        )
    
        orders.each do |order|
          if order.is_paid?
            raise "order #{order.order_no} has already paid"
          end
    
          order.payment = payment
          order.save!
        end
      end
    

    既没有看到使用悲观锁,订单上也没有创建乐观锁,方法内也并没有分布式锁做排他调用保证

    create_table "orders", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
      t.integer  "user_id"
      t.integer  "product_id"
      t.integer  "address_id"
      t.string   "order_no"
      t.integer  "amount"
      t.decimal  "total_money", precision: 10, scale: 2
      t.datetime "payment_at"
      t.datetime "created_at",                                               null: false
      t.datetime "updated_at",                                               null: false
      t.integer  "payment_id"
      t.string   "status",                               default: "initial"
      t.index ["order_no"], name: "index_orders_on_order_no", unique: true, using: :btree
      t.index ["payment_id"], name: "index_orders_on_payment_id", using: :btree
      t.index ["user_id"], name: "index_orders_on_user_id", using: :btree
    end
    
    
  • 也没有考虑地址可能修改的问题

  • 貌似代码没有考虑concurrency问题

  • Ruby 的爬虫世界 at 2016年12月27日

    任务管理简单点可以用sidekiq,worker放在docker里面,集群部署不是啥问题~

  • 简单点可以以行做为最小单位来保存,记录行的初始状态和最后编辑结果

    多个行操作对应一次操作动作(实现复制粘贴多行的redo需求),前进和后退的操作就转换成为了每个操作动作对应行历史的批量操作

    如果所有结果只能存在内存里,需要借限制保存的行数或操作动作数来限制总内存使用。