Ruby China
  • Topics
  • 招聘
  • Wiki
  • 酷站
  • Gems
  • Sign Up
  • Sign In
Rei
@Rei
Admin
NO. 1 / 2011-10-28

[email protected]
深圳
186 Topics / 9147 Replies
730 Followers
0 Following
11 Favorites
中下水平 Rails 程序员
Reward
GitHub Public Repos
  • writings 941

    [Closed] Source code of writings.io

  • alipay 732

    Unofficial alipay ruby gem

  • code_campo 291

    [Closed] Source code of http://codecampo.com

  • asciidoctor-pdf-cjk-ka... 101

    **no longer maintained**

  • asciidoctor-htmlbook 31

    Asciidoctor HTMLBook is an Asciidoctor backend for converting AsciiDoc documents to HTMLBook docu...

  • material-ui 17

  • htmlrenderer 12

  • rich-text-editor 12

  • rails-chatgpt-demo 8

  • rails-app 7

    A Rails project template lets me start new projects quickly.

More on GitHub
  • Overview
  • Topics
  • Replies
  • Favorites
  • Following
  • Followers
  • 感觉 Ruby China 社区越来越冷清了。。。 at September 22, 2018

    这个对 Web 的看法比较狭隘,一方面,没有认识到 Web 是目前最流行的开放平台:

    1. 全球领先的 AI 公司 Google 主打产品 Google 搜索和 Youtube 是通过什么平台服务的?
    2. 阿里巴巴的现金牛淘宝天猫是通过什么平台服务的?(提醒:App 里面用了不少 Web 技术)
    3. 微信接下来对人们生活影响最大的封闭应用平台——小程序是基于什么技术开发的?

    另一方面,夸大了大数据、AI 的应用场景,AI 跟 Web 不是竞争关系。只有少数应用像 Google 搜索那样以大数据和 AI 为核心竞争力,大部分场景只能用数据和 AI 改良部分的功能——例如让广告投放更准确、风控更可靠。下一个以 AI 为核心竞争力的领域可能是自动驾驶,但是所有人都要去做自动驾驶吗?一窝蜂的投入大数据和 AI 领域,小心以后工作就是当个财务报表分析员。

    我维护过一个面向全球客户的关键后台服务,以 Mobile App 为终端,不提供 Web 界面,一样基于 Rails 开发。一个后台服务需要数据库、鉴权、序列化、后台任务等等功能,用 Ruby 还是用 Go 没有什么不同,难点不在语言而在业务。

    马云是个商人、老板,听老板讲话不要说什么就是什么,而是分析背后的目的,难道有了 AI 就要基于 AI 重写淘宝?大家都搞 AI 去就不用跟淘宝在电商领域竞争了。

    最后推荐一篇文章:Betting on the Web https://joreteg.com/blog/betting-on-the-web

  • 新人求教:终端不自动载入 RVM 环境 at September 21, 2018

    Docker

  • 新人求教:终端不自动载入 RVM 环境 at September 21, 2018

    要额外处理 PATH 问题。

  • 新人求教:终端不自动载入 RVM 环境 at September 20, 2018
    1. 不建议看 wiki
    2. 不建议用 RVM
    3. 建议装系统源里的 Ruby
  • 想请教一下有关 rails test 无法正确运行的问题 at September 12, 2018

    估计是那几个 gem 导致错误捕捉除了问题:

    group :test do
      gem 'rails-controller-testing', '1.0.2'
      gem 'minitest-reporters', '1.1.14'
      gem 'guard', '2.13.0'
      gem 'guard-minitest', '2.4.4'
    end
    

    我看了下这本书只说了替换 Gemfile 没说更换这些 gem 的理由是什么,对初学者很不利。

    我推荐用《Rails 5 敏捷开发》这本书 https://book.douban.com/subject/27615703/

  • 想请教一下有关 rails test 无法正确运行的问题 at September 12, 2018

    贴代码和运行结果。

  • 想请教一下有关 rails test 无法正确运行的问题 at September 12, 2018

    一个 test case 是指一个 test "..." do end 块,可以随意自己添加。

  • 想请教一下有关 rails test 无法正确运行的问题 at September 12, 2018

    错误打出异常栈是正常的,不然不好 debug,应该是书缺少提示了。

    在同一个 test case 里面,遇到 error 或者 fail 之后,后面的代码就不执行了,因为很可能也会失败,没必要执行下去。test case 之间是独立的。

  • 想请教一下有关 rails test 无法正确运行的问题 at September 12, 2018

    路由未定义。

    errors 打出错误栈是正确的,书里有没有写“以下省略部分输出”?

  • [折腾向] 使用 systemd 来管理你的 Rails 应用 at September 11, 2018

    说 docker 的说说用什么编排工具啊,总不能一台台上去操作吧。

  • [折腾向] 使用 systemd 来管理你的 Rails 应用 at September 11, 2018

    创建目录、链接文件、运行迁移、重启进程,这些工作总要有工具做啊。

    cap 就是个远程执行工具。

  • [折腾向] 使用 systemd 来管理你的 Rails 应用 at September 11, 2018

    我用 cap 部署,systemd 监视进程。

  • Why Sometimes I Write WET Code at September 09, 2018

    写第三次再提炼。

  • 如何本地编译 asset ,然后推送到云端使用? at September 08, 2018

    云端的部署架构是什么?

    如果是典型的 nginx 跟 app 在同一服务器,要把 nginx 的 root 指向 public 目录;如果是 heroku,则需要设置 RAILS_SERVE_STATIC_FILES 环境变量让 rails 进程处理静态文件,但这通常会在前面加一层 CDN。

  • 关于 Rails 写移动端的困惑,希望大佬们能指点一二! at September 06, 2018

    …你先买本入门书把例子做完。

  • 关于 Rails 写移动端的困惑,希望大佬们能指点一二! at September 06, 2018

    API 控制器收到的数据存到模型层,后台控制器再从模型层查数据。

  • 大家是如何处理 Rails 应用的 Model 层和数据库层的数据校验的? at September 05, 2018

    用 validates 比较容易收集错误信息,而且不用访问数据库。
    数据库异常不好处理错误信息,而且耗费了网络请求。

  • ChangeSet 的思路 Rails 会借鉴么? at September 05, 2018

    不承认对象客观存在,又变着法子模仿对象的功能,只能说开心就好。

  • 在 rails 里面 devise 这样的东西 java 或者 python 里面存在吗? at September 05, 2018

    你满嘴跑火车偶尔说对一两句话不出奇,我点赞对事不对人。看我博客发布日期,你确定不是看过我博客后记了下来?

  • 在 rails 里面 devise 这样的东西 java 或者 python 里面存在吗? at September 05, 2018

    可笑 https://chloerei.com/2013/11/22/you-do-not-need-these-gems/

  • ChangeSet 的思路 Rails 会借鉴么? at September 05, 2018

    Ops, 我忘了 elixir 相对 erlang 的改变之一就是增加了可重复绑定的变量,这在 erlang 认为是不纯。

    直接修改实例变量,不比新增一个 struct 然后覆盖它更直观吗?

    order.status = 'paid'
    
  • ChangeSet 的思路 Rails 会借鉴么? at September 05, 2018

    不懂你的观点。

    Struct 用来约束数据结构,数据一旦生成就不可变,要改变的时候只能新增一个数据。例如:

    defmodule Order do
      defstruct number: '', status: 'open'
    end
    
    iex> order = %Order{ number: '20180101' }
    %Order{number: '20180101', status: 'open'}
    iex> order_paid = %{order | status: 'paid'}
    %Order{number: '20180101', status: 'paid'}
    iex> order
    %Order{number: '20180101', status: 'open'} # 旧的数据依然存在
    

    此时内存中存在两份 number 为 20180101 的订单,就因为 elixir 的变量不可变,新变量只是在假装不知道旧数据存在罢了。我认为这不是很好的对现实关系的映射。

  • ChangeSet 的思路 Rails 会借鉴么? at September 05, 2018

    用脚可以拿筷子吗?练练也是可以用的,但是有手的情况下何须用脚拿筷子。

    无状态在处理数据流的时候也许有不少优点,但在跟 DB 交互这里,DB 作为数据流终点就是有状态的,强用无状态实现不是一个优势。

  • ChangeSet 的思路 Rails 会借鉴么? at September 05, 2018

    看了下文档,ChangeSet 不就是 Elixir 这样的函数式语言没有实例变量而不得不把所有变量通过参数传递么。

    而且用起来跟 ActiveRecord 没啥区别:

    changeset = User.changeset(%User{}, %{age: 0, email: "[email protected]"})
    {:error, changeset} = Repo.insert(changeset)
    changeset.errors #=> [age: {"is invalid", []}, name: {"can't be blank", []}]
    
    user = User.new(age: 0, email: "[email protected]")
    user.save
    user.errors #= > <#ActiveModel::Errors ... @message={:age=>["is invalid"], :name=>["cant be blank"]}
    

    看 Ruby 还短一点。

    ChangeSet 用作 validation 一个坏处是很容易被跳过,不能当作数据入库前的守门人。用作 filter 还比较合理。Ruby 2.5 的 yield_self 就可以方便写出链式过滤器调用了。 https://blog.bigbinary.com/2017/12/12/ruby-2-5-added-yield_self.html 下一版也许会把 yield_self 增加一个 alias then。

    学习新语言看到新特性,就感觉无所不能,忘了以前是怎么做的,这是一种通病。函数式语言推广者把“无状态”奉为金科玉律,无视现实世界还有很多有状态的事物,成也于此败也于此。

  • 服务器如何强行指定一次请求头的 Content-Type 为 application/json at September 04, 2018

    不改。对接过 Web、Android、iOS、C++,设请求头都没有问题。说困难是他们忽悠你。

  • 在 rails 里面 devise 这样的东西 java 或者 python 里面存在吗? at September 04, 2018

    举了个例子 https://ruby-china.org/topics/37434#reply-346228

  • 系统使用 Devise 做的登录,有个需求 [同一帐号被另一台机器登录,本机器被强制退出登录],求大神指点一下 at September 04, 2018

    十楼方法是增加一个过滤器判断额外的 token,不改变 devise 内部,原理一样但更安全。

  • 系统使用 Devise 做的登录,有个需求 [同一帐号被另一台机器登录,本机器被强制退出登录],求大神指点一下 at September 04, 2018

    这个问题是个好例子说明为什么 devise 很难用。

    如果是自己实现的用户登录机制,那么很容易会知道应该改哪里。通常来说,user 应该带有一个 token 字段存在 session 中,访问的时候通过 token 查用户。如果要注销旧的登录态,只要把 token 重置就行了。

    那么 devise 怎么做呢,应该 reset 哪个 token?我也不知道,因为内部实现太复杂了,查看数据模式根本没有这个字段,我尝试读一下源码。

    首先根据我以前读源码的经验,我先找 devise 的 session controller:

    https://github.com/plataformatec/devise/blob/3b0bc08ec67dd073ddd6d043c71646c2784ced6c/app/controllers/devise/sessions_controller.rb#L18-L24

    def create
      self.resource = warden.authenticate!(auth_options)
      set_flash_message!(:notice, :signed_in)
      sign_in(resource_name, resource)
      yield resource if block_given?
      respond_with resource, location: after_sign_in_path_for(resource)
    end
    

    关键在于 sign_in(resource_name, resource) 这一行,继续找 sign_in 如何实现:

    https://github.com/plataformatec/devise/blob/715192a7709a4c02127afb067e66230061b82cf2/lib/devise/controllers/sign_in_out.rb#L33-L55

    def sign_in(resource_or_scope, *args)
      options  = args.extract_options!
      scope    = Devise::Mapping.find_scope!(resource_or_scope)
      resource = args.last || resource_or_scope
    
      expire_data_after_sign_in!
    
      if options[:bypass]
        ActiveSupport::Deprecation.warn(<<-DEPRECATION.strip_heredoc, caller)
        [Devise] bypass option is deprecated and it will be removed in future version of Devise.
        Please use bypass_sign_in method instead.
        Example:
          bypass_sign_in(user)
        DEPRECATION
        warden.session_serializer.store(resource, scope)
      elsif warden.user(scope) == resource && !options.delete(:force)
        # Do nothing. User already signed in and we are not forcing it.
        true
      else
        warden.set_user(resource, options.merge!(scope: scope))
      end
    end
    

    关键在最后一行 warden.set_user(resource, options.merge!(scope: scope)),warden 是另一个 gem,在到另一个库里搜 set_user 做了什么:

    https://github.com/wardencommunity/warden/blob/5b3cbd5bef67cbe399bb7007537bc4841bbee772/lib/warden/proxy.rb

    def set_user(user, opts = {})
      scope = (opts[:scope] ||= @config.default_scope)
    
      # Get the default options from the master configuration for the given scope
      opts = (@config[:scope_defaults][scope] || {}).merge(opts)
      opts[:event] ||= :set_user
      @users[scope] = user
    
      if opts[:store] != false && opts[:event] != :fetch
        options = env[ENV_SESSION_OPTIONS]
        if options
          if options.frozen?
            env[ENV_SESSION_OPTIONS] = options.merge(:renew => true).freeze
          else
            options[:renew] = true
          end
        end
        session_serializer.store(user, scope)
      end
    
      run_callbacks = opts.fetch(:run_callbacks, true)
      manager._run_callbacks(:after_set_user, user, self, opts) if run_callbacks
    
      @users[scope]
    end
    

    关键是这个 session_serializer.store(user, scope),在找找 session_serializer 是什么鬼,然后找到这里:

    https://github.com/wardencommunity/warden/blob/5b3cbd5bef67cbe399bb7007537bc4841bbee772/lib/warden/session_serializer.rb#L23-L28

    def store(user, scope)
      return unless user
      method_name = "#{scope}_serialize"
      specialized = respond_to?(method_name)
      session[key_for(scope)] = specialized ? send(method_name, user) : serialize(user)
    end
    

    我这里跳跃一下,直觉告诉我 warden 里面都是些 proxy 方法,也许 devise 用到的 serialize 是在 deivse 里面定义的,于是我回去搜 devise 里面有没有 serialize 相关的方法,于是搜到这个:

    https://github.com/plataformatec/devise/blob/715192a7709a4c02127afb067e66230061b82cf2/lib/devise/models/authenticatable.rb#L233-L240

    def serialize_into_session(record)
      [record.to_key, record.authenticatable_salt]
    end
    
    def serialize_from_session(key, salt)
      record = to_adapter.get(key)
      record if record && record.authenticatable_salt == salt
    end
    

    我也不知道是不是,看起来 devise 是通过 to_key 和 authenticatable_salt 定位用户的。

    在 ActiveReocrd 里 to_key 约等于 id,不可变,那么我们最好从 authenticatable_salt 入手,搜一下 authenticatable_salt:

    https://github.com/plataformatec/devise/blob/715192a7709a4c02127afb067e66230061b82cf2/lib/devise/models/authenticatable.rb#L98-L99

    def authenticatable_salt
    end
    

    https://github.com/plataformatec/devise/blob/715192a7709a4c02127afb067e66230061b82cf2/lib/devise/models/database_authenticatable.rb#L137-L140

    # A reliable way to expose the salt regardless of the implementation.
    def authenticatable_salt
      encrypted_password[0,29] if encrypted_password
    end
    

    根据加载的模块不同,authenticatable_salt 的实现不一样。留意 authenticatable 里面的实现,authenticatable_salt 跟 encrypted_password 绑定,这样可以实现修改密码之后 authenticatable_salt 一起变更,但这怎么解决顶楼的问题呢?

    我建议是新增一个字段,然后把 authenticatable_salt alias 过去。

    class User < ActiveRecord::Base
      has_secure_token :auth_token
    
      def authenticatable_salt
        auth_token
      end
    end
    

    然后要改写 session_controller,在每次登录之后 reset remember_token:

    def create
      self.resource = warden.authenticate!(auth_options)
      set_flash_message!(:notice, :signed_in)
      resource.regenerate_auth_token # <- 重置 auth_token
      sign_in(resource_name, resource)
      yield resource if block_given?
      respond_with resource, location: after_sign_in_path_for(resource)
    end
    

    以上方法我没有实践过,不保证能用。

    读源码是最费时的一种方法,有的人可能会提醒我,用 Google 搜一下,也许会有现成答案。没错,我搜了一下发现这个特性有人写成了 Gem,https://github.com/phatworx/devise_security_extension (session_limitable)。大多数的 devise 问题都能搜一搜,粘贴段代码,或者装个 gem 解决,但是用户登录是系统的核心模块,这样做真的对吗,如果用户登录的原理都搞不懂,怎么能确保系统是安全的呢?

    所以我的建议是别用 devise,读 devise 源码的耗时远远大于自己写,当然楼主维护现有系统是没得选了。这回复得比较啰嗦,我留作以后讨论 devise 的例子。

  • 部署程序如何能达到一定并发量? at September 03, 2018

    接入 https://newrelic.com/ 再跑压测,看 NewRelic 分析。

  • Prev
  • 1
  • 2
  • …
  • 32
  • 33
  • 34
  • 35
  • 36
  • …
  • 273
  • 274
  • Next
关于 / RubyConf / Ruby 镜像 / RubyGems 镜像 / 活跃会员 / 组织 / API / 贡献者
由众多爱好者共同维护的 Ruby 中文社区,本站使用 Homeland 构建,并采用 Docker 部署。
服务器由 赞助 CDN 由 赞助
iOS 客户端 / Android 客户端 简体中文 / English