• #2 楼 @dotcomXY 没上过 squarespace, shopify,有空研究一下,能发展成一个开源的购物网站那就更棒了。

  • #1 楼 @Rei 这是一个悲伤的故事。😂

  • 第三版预览版现在有的看不?

  • 开源 Tower 的编辑器 Simditor at 2014年08月13日

    #66 楼 @kshift 原来是没有开源,弄的我重复看了好几遍文档,最后都没有发现才来 ruby china 找答案了。

  • 我想知道,用 PostgreSQL 后,因为事务的问题,参考:https://ruby-china.org/topics/19499?page=1#reply28 隔离级别是修改为repeated read还是说使用默认的+乐观锁呢?

  • 可以尝试使用这个 gem,https://github.com/leshill/handlebars_assets 当然,其实在hbs文件后面,加上hbs.erb,然后<img src="<%=asset_path('logo.png')%>">也是可行的。

  • 用正则提出,然后用 markdown 转成 html,这个是我的做法。也可以直接转成 html。 代码地址: 从内容处提出 user 生成一个 notifications

    def convert_content
      if self.content.include?("@")
        users = find_user_in_content
        users.each do |user|
          url = "[@#{user.name}](/users/#{user.id})"
          self.content.gsub!(/(@#{user.name})/, url) 
        end
      end
      self.content = markdown(self.content)
      true
    end
    
    def format_user_in_content
      self.content.scan(/@([\w\u4e00-\u9fa5]{2,20})/).flatten
    end
    
    def find_user_in_content
      User.where(name: format_user_in_content)
    end
    
    def markdown(text)
      markdown_render = Redcarpet::Render::HTML.new(hard_wrap: true, no_styles: true)
      markdown = Redcarpet::Markdown.new(markdown_render, autolink: true, no_intro_emphasis: true) 
      markdown.render(text).html_safe
    end
    
  • 如何确保订单状态安全性 at 2014年04月21日

    #13 楼 @HungYuHei 这样的吗? 但是如果像是 before_save 或者 after_save 的话,如果存 a 之后,update b 和 c。但是不要出现 a 存了,而 b 和 c 没有 update 的情况。

    Model A < ActiveRecord::Base
      after_save do
        transaction do
          b.update!(xxx: xxx)
          c.update!(xxxx: yyyy)
        end
      end
    end
    

    像这样的情况,应该怎么把 A 也放到事务里?还是说都用around_save

  • 如何确保订单状态安全性 at 2014年04月15日

    #2 楼 @5swords log 表使用 MySQL 存怎么样?

  • 如何确保订单状态安全性 at 2014年04月15日

    涉及金额的运算,要使用事务,而不是 callback. 事务里,加上线程的保护: http://api.rubyonrails.org/classes/ActiveRecord/Locking/Pessimistic.html

  • 我觉得这是一个很复杂的问题,使用 Conerns 就这个意思:

    为什么呢?我避免将一个大的 ActiveRecord 类里面的一部分方法放到某个关联类或者模块里面,然后将它们混入。我有一次听到这样的说法:
    
    Any application with an app/concerns directory is concerning. 我同意,组合优于继承。但是,像这样使用混入就像是将混乱放到 6 个不同的抽屉然后关上它。确实,它表面上看去干净多了。但是垃圾抽屉的做法实际上使得它难以识别并且难以分解和提取业务模型。
    

    使用 Conerns 就是把一个大的 Model,抽出来,然后放入 Conerns,或者是把 Model 里的方法分类的放入不同的 Conerns 里,例如这样:

    class User < ActiveRecord::Base
      ...
      #Virtual Attributes
      def full_name
        [first_name, last_name].join(' ')
      end
    
      def full_name=(name)
        split = name.split(' ', 2)
        self.first_name = split.first
        self.last_name = split.last
      end
      ...
    end
    

    上面是一个 User 里的一个Virtual Attributes,我可以使用 Conerns,把Virtual Attributes挪出去。添加一个virtual_attributes.rb,到 Conerns 里:

    class User
      module VirtualAttributes
        extend ActiveSupport::Concern
    
        def full_name
          [first_name, last_name].join(' ')
        end
    
        def full_name=(name)
          split = name.split(' ', 2)
          self.first_name = split.first
          self.last_name = split.last
        end
      end
    end
    
    class User < ActiveRecord::Base
      include VirtualAttributes 
      ...
    end
    

    这样 Model 就瘦了一圈,当我要找 User 的 VirtualAttributes 时,到这个 Conerns 里找就可以了。一下方便了很多,也简洁了。Conerns 是非常通用的,所以我主要想讲一下我对 Services 用法的理解。


    把刚刚的 VirtualAttributes 里放到 Services 里,看怎么样?

    class UserVirtualAttributes
      def initialize(user)
        @user = user
      end
    
      def full_name
        [@user.first_name, @user.last_name].join(' ')
      end
    
       def full_name=(name)
         # 这个方法比较复杂,所以先不写
       end
    end
    

    调用:

    @user = User.find(params[:id])
    @user_full_name = UserVirtualAttributes.new(@user).full_name
    

    这个看起来貌似没有使用 Conerns 那么酷哦!当然,这种情况,就不适合使用 Services。那什么时候适合使用 Services?

    其实 Services 是一个面向对象的思想,Rails 把所有东西都放到 MVC 里,所以当我第一次接触 Rails 的时候,顿时觉得和我认识的面向对象有点不太一样。我说说我对面向对象的理解,举个人骑自行车的简单例子来说说我理解的面向对象。

    如果我要做一个人骑自行车的程序,至少要三个类,分别是:

    人(手、腿等),骑的动作(脚踩一次脚踏板 => 自行车运动范围),自行车(轮,脚踏板等)
    
    class People
      ...
      def right_left
        ...
      end
    end
    
    class Bike
      ...
      def right_pedal
        ...
      end
    end
    
    class RideBike
      ...
      def ride
        @people = People.new
        @bike = Bike.new
        ...
      end
    end
    

    大概意思这样子,感觉有点瞎扯,代码就不详细写下去了。主要要表达的意思就是,面向对象的思维就是把事物更合理的抽象出来的思想。

    所以上面的 full_name 属于 User 的属性,应该放倒 User 里,那是不是我们现在 User 里的所有方法都是正确的呢?如果从面向对象的思想来说,我们常用的密码校验,密码加密等事情,就是不应该放在 User 里的,而应该抽象出来放到Services中,如7种重构膨胀 ActiveRecord 模型的方法说的一个例子:

    class UserAuthenticator
      def initialize(user)
        @user = user
      end
    
      def authenticate(unencrypted_password)
        return false unless @user
    
        if BCrypt::Password.new(@user.password_digest) == unencrypted_password
          @user
        else
          false
        end
      end
    end
    

    调用方法:

    UserAuthenticator.new(user).authenticate(params[:password])
    

    而大部分教材和我们管用的做法是:

    class User < ActiveRecord::Base
      ...
      def authenticate(unencrypted_password)
        if BCrypt::Password.new(password_digest) == unencrypted_password
          self
        else
          false
        end
      end 
      ...
    end
    

    上面的案例我觉得是一个可以使用 Services 的情况。因为我觉得 UserAuthenticator 不属于 User 的时期。把 UserAuthenticator 放在 User 里,感觉就像:要判断一个人是否生病,还得用自己的方法。而我觉得正确的表达是:使用特定的Services,来检查这个人是否生病了


    我的观点是 Services 这个问题是非常复杂的,初建项目可以不需要考虑这么深层的问题。 我觉得 Services 最难使用的是如何保证团队里的思想一致性,情况就像如果我使用上面的UserAuthenticator,而团队里的人员觉得放在 User 里更合适,诸如此类的观点不一致的情况,会导致整个项目变得更凌乱,就针对这个问题,我没有想过有什么特别好的办法。 所以我还特别想了解,各个团队间应该怎么解决这样的问题比较好呢?

  • #3 楼 @Peter 其实用capistrano是不是做不到类似chef部署多台服务器?

  • 庆生电子书七折优惠 at 2014年04月01日

    赶在活动结束前入手了,翻译的质量不错,都入手了有。 今日入手了《Rails Guides》

    我想问问之前在淘宝买的《Ruby on Rails 教程》现在更新需要做什么操作呢?

  • 可惜啊,只在北京。😄

  • #1 楼 @rociiu 怎么选择用 concerns,还是 services?只使用 services 了?

  • 如果我没记错的话,client_side_validations不对 rails4 支持,并且不在更新了。

  • :thumbsup: :thumbsup: 👍 👍

  • #9 楼 @coolesting 这是一个有人脉觉得有技术重要,一个有技术觉得有人脉重要的年代。 除非做的是 zf 项目,不然我觉得最关键还是执行力吧。

  • IE 是什么?

  • 认真你就输了。

  • rubysl在这里起到什么作用?

  • @admin_articles = Admin::Article.all.page(params[:page]).per(5)
    
    在View中写入<%= paginate @admin_article %>
    

    因为你的<%= paginate @admin_article %>应该改成<%= paginate @admin_articles %>少了一个 s。

  • 一段 HTMLBars 的 slide at 2014年01月25日

    这玩意几时完成?