• 一些奇怪的 Ruby 行为 at 2022年05月23日

    ruby 不支持这样的嵌套方法定义,如果开启了 warning, 会看到如下错误:

    irb -w
    Foo.new.method_one
    Foo.new.method_one
    (irb):3: warning: method redefined; discarding old method_two
    (irb):3: warning: previous definition of method_two was here
    
  • 你可以给 Symbol 加个 patch

    class Symbol
      def call(*args, &block)
        ->(caller, *rest) { caller.send(self, *rest, *args, &block) }
      end
    end
    

    这样任意的 proc shorthand 写法就可以写成

    arr.map(&:[].(:a))
    

    但是这样的可读性反而比不上非 shorthand 写法,记得 ruby 有讨论一个新的语法支持 shorthand argument, 语法类似这样,&0, &1, &N 代表 proc 的第 N 个元素,不过还没有被接受:

    arr.map(&0[:a])
    
  • 我有帮别人测试过从 RDS 迁移到 Aurora, 差不多 Aurora 要贵 30%, 忘记具体是哪项收费了,不过他们是单 RDS, 没有 read, 不过他们后来还是迁移了,没有遇到什么坑

  • ruby quiz at 2021年01月11日

    one line style

    'idP111~nm~~nm xxx ~~~~~~~~ ~~id~~br~~~qt10'.scan(/(id|nm|qt|pr)(.+?[^~](?:~~)*(?=(?:~[^~])|$))/).to_h.transform_values{|s| s.gsub('~~', '~')}
    
  • 111 at 2020年10月31日

    促进 GDP,是好事 😂😂😂

  • Ruby 默认都是引用操作,你自定义一个类,测试一下就知道 array index 也是引用操作,不存在你说的性能消耗问题:

    class Foo
        attr_accessor :bar
    end
    
    a = [Foo.new, Foo.new, Foo.new]
    b = a[1..-1]
    
    b[0].bar = 42
    a[1].bar == b[0].bar
    => true
    
  • 这种需求下,你的 DFA 结构没有必要添加 is_end / value,直接用 hash 是否为空来判断就可以知道是否是最后一个,另外代码里面用了很多 clone,会很消耗内存,可以用 inject:

    def add_word(word)
      word = word.strip.gsub(%r{[^\p{Han}+/ua-zA-Z0-9]}, '')
      word.chars.inject(self.words) do |words, char|
        if !words.key?char)
          words[char] = {}
        end
        words[char]
      end
    end
    
    def filter(word)
      sensitive_word = ''
      word = word.strip.gsub(%r{[^\p{Han}+/ua-zA-Z0-9]}, '')
      word.chars.each_with_index.inject(self.words) do |words, (char, index)|
        if words.key?(char)
          sensitive_word += char
          break if words[char].empty?
          # 如果被检测的词已是最后一个,但关键字还不是最后,则返为空
          return '' if index == word.size - 1
          words[char]
        else
          # 如果上一步在关键字中,这次又不在关键字中,需要重新初始化检测
          if !sensitive_word.empty?
            sensitive_word = ''
            words = self.words and redo
          else
            words
          end
        end
      end
      sensitive_word
    end
    

    以上代码是手写的,filter 部分应该还能再简化一下

  • 比如 PHP

  • 你在 location 里面添加这 2 个试试看,具体说明请参考 nginx 的文档:

    proxy_http_version 1.1;
    proxy_set_header Connection "";
    
  • 把 Nginx 配置贴上来看看?

  • 看这个 TIME_WAIT 是 nginx 和 puma 之间的连接,试试设置 nginx upstream keepalive 应该能解决这个问题。

  • 可以多创建一个表,记录被用户单条忽略的动态:

    ignored_events
    ------------------------
    user_id,  event_id
    3      ,  10
    

    然后加一个 not exists 或者 not in 查询

    select e.* from events e, event_subscribers es
        where e.user_id = es.subscribed_user_id
          and es.user_id = 3
          and e.id not in (
            select id from ignored_events ie
              where ie.user_id = 3
          )
    
    
  • 文章写的好详细,赞。

    如果担心大数据量的性能问题,还有一个选择是用 PostgreSQL 的 array,可以给它设置 GIN 类型的索引,本质上是一个全文索引的字段,Rails 也有相关的 gem : https://github.com/tmiyamon/acts-as-taggable-array-on

  • [*0..5, *2..8, *3..12, 2, 2, 2, 2].each{|i| print' '*(40-2*i-i/2)+'*'*(4*i+1+i)+"\n"}
    
  • 可以看一下 ProxySQL 它能满足你提到的这些需求: https://github.com/sysown/proxysql

    另外一个是 Vitess 但我对它不熟,听 Github 的人说他们在评估这个,你也可以看一下: https://github.com/vitessio/vitess

  • ActiveJob 目的是为了并发/异步执行,改成长度为 1 的队列,未免削足适履,更合适的解决方案是用 flock,用 Exclusive lock 和 None blocking 来保证一个文件只能被一个 JobWorker 处理,同时也有并发处理多文件的能力

    f = File.open(...)
    if f.flock(File::LOCK_EX | File::LOCK_NB)
      ...
    end
    
  • 直觉是不可能,在我自己机器上跑了一下,结果是相反的,你的 ruby 是什么版本?

    2.3.2 :018 > Benchmark.measure { maxa(1000)}
     => #<Benchmark::Tms:0x007fcd7a884b78 @label="", @real=3.692405005916953, @cstime=0.0, @cutime=0.0, @stime=0.040000000000000036, @utime=3.6, @total=3.64> 
    2.3.2 :019 > Benchmark.measure { maxf(1000)}
     => #<Benchmark::Tms:0x007fcd7b027b00 @label="", @real=0.8660073862411082, @cstime=0.0, @cutime=0.0, @stime=0.009999999999999898, @utime=0.8300000000000001, @total=0.84> 
    

    好像在2.4测试就反过来了,是因为2.4的那个Array#max实现更新吗,等下再看看...

  • 推模式问题在于任何影响订阅关系的行为,比如屏蔽或者取消屏蔽,还需要对已经推送的 event 进行修改

  • 和推不一样的,推的模式在产生 event 的时候,需要写入大量数据,而且这种设计也没有 屏蔽/取消屏蔽 导致数据不正确的问题

  • 我觉得拉的模式缺点讲得不正确,把 event 和 friendship 强关联的设计是这个造成这个缺点的主要原因,而不是拉模式本身的问题。

    正确设计应该有一个中间表,比如 event_subscribers,表结构是这样的:

    user_id, subscribed_user_id
    3      , 4
    3      , 8
    1      , 4
    1      , 10
    

    SQL 查询是固定的:

    select events.* from events, event_subscribers
        where events.user_id = event_subscribers.subscribed_user_id and event_subscribers.user_id = 3
    

    所有的屏蔽,过滤都是对 event_subscribers 这个中间表数据做操作

  • 可以先用数组的前一个元素做 group_by,然后用 map! 方法将后一个元素做 replace:

    data = [['A', '123'], ['A', '1223'], ['A', '12343'], ['A', '122XX33'], ['B', '678'], ['B', '612378'], ['B', '67XX8'], ['C', '100'], ['C', '1000']]
    
    data.group_by(&:first).each{|_, v| v.map!(&:last)}
    
    # => {"A"=>["123", "1223", "12343", "122XX33"], "B"=>["678", "612378", "67XX8"], "C"=>["100", "1000"]} 
    
  • 除了添加额外字段对比 session 之外,你也可以用一样的思路依赖 devise 内置的 model Trackable(通常我都会建议在使用 devise 的项目中设置这个模块)的字段 sign_in_count,然后写一个 hook,几行代码就可以满足你的需求:

    Warden::Manager. after_authentication do |record, warden, options|
      warden.session(options[:scope])[:sign_in_count] = record.sign_in_count
    end
    
    Warden::Manager.after_fetch do |record, warden, options|
      if record.sign_in_count != warden.session(options[:scope])[:sign_in_count]
        warden.logout(options[:scope])
        throw :warden, :scope => options[:scope], :message => "Signin from another IP address #{record.last_sign_in_ip}"
      end
    end
    

    基本上做 devise 的扩展都是通过 hook 来进行,非常简洁方便。

  • 想了一个无需默认 0 Hash 的一行版:

    a.inject({}){|m, (k, v)| m.merge(k => v.to_i) {|k, old, new| old + new} }
    
  • 这个弱鸡的换行问题 at 2017年12月11日
    params.values_at(:begin_integral, :end_integral, ...).all?(&:present?)
    
  • 你这个只有对单个 created_at 进行查询,RTree 索引在这里和 BTree 相比没有优势

  • 对,ActiveRecord 的 PG 支持有 range 这个类型,Mysql 就比较落后了,得自己去实现,就是提到的扩展问题 3: http://edgeguides.rubyonrails.org/active_record_postgresql.html#range-types

  • Ruby 爬虫框架 at 2017年11月07日

    现在的爬虫趋势是用 headless chrome,通过 amazon lambda 运行,之前写过 2 个脚本,支持 ajax,加上 css selector/xpath,用来抓数据非常方便,大规模爬虫,代理IP,都很容易设置。

    如果做爬虫框架的话,求支持这种模式。

  • 有 etag 和 last-modified