<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>chriszou (Chris)</title>
    <link>https://ruby-china.org/chriszou</link>
    <description></description>
    <language>en-us</language>
    <item>
      <title>BitBar 使用 Ruby 脚本，解决无法使用 Gem 的问题，以及读写文件路径存在空格的问题</title>
      <description>&lt;p&gt;&lt;a href="https://github.com/matryer/xbar" rel="nofollow" target="_blank" title=""&gt;BitBar&lt;/a&gt;(现改名为 xbar) 是一个开源的 Mac 小工具，它可以把任何东西放到 MacOS 的状态栏上面，我现在一般用它来做 TODO list。如下图所示&lt;/p&gt;

&lt;p&gt;&lt;img src="https://images4blogs.oss-cn-hangzhou.aliyuncs.com/iShot2021-05-03%2017.36.38.png" title="" alt="iShot2021-05-0317.36.38"&gt;&lt;/p&gt;

&lt;p&gt;不过，刚开始使用的时候，遇到这个一个问题，就是无法使用 gem，因为 BitBar 默认使用的 ruby 版本是系统版本，而我通常使用 rvm。翻了 BitBar 的 github issues 之后，找到这样一个&lt;a href="https://github.com/matryer/xbar/issues/75#issuecomment-239941497" rel="nofollow" target="_blank" title=""&gt;解决办法&lt;/a&gt;：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env ruby&lt;/span&gt;

&lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'USING_RVM'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="c1"&gt;# Re-run this script with RVM's default Ruby, after setting up the RVM path,&lt;/span&gt;
  &lt;span class="c1"&gt;# and setting USING_RVM to true, so that this sentry code won't run the second&lt;/span&gt;
  &lt;span class="c1"&gt;# time through.&lt;/span&gt;
  &lt;span class="nb"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&amp;lt;-&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
      export USING_RVM=true
      export PATH="~/.rvm/bin:$PATH"
      rvm-auto-ruby &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expand_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kp"&gt;__FILE__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;
&lt;/span&gt;&lt;span class="no"&gt;    EOF&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;# Return the exit code from running the script with RVM:&lt;/span&gt;
  &lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="vg"&gt;$?&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exitstatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_i&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'faraday'&lt;/span&gt; &lt;span class="c1"&gt;# 可以正常使用Gem了&lt;/span&gt;
&lt;span class="c1"&gt;# 以下正常写你的脚本代码&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不过，由于我的这个 script 文件是放在 iCloud 目录下的，具体路径是 &lt;code&gt;/Users/myusername/Library/Mobile Documents/com~apple~CloudDocs/apps/BitBarPlugins&lt;/code&gt;，可以看到，中间有一个空格，于是，在代码运行到&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rvm-auto-ruby #{File.expand_path(__FILE__)}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这一行的时候，遇到这样的错误提示：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Traceback (most recent call last):
ruby: No such file or directory -- /Users/myusername/Library/Mobile (LoadError)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;解决办法是：
&lt;code&gt;require 'shellwords'&lt;/code&gt;
然后 &lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rvm-auto-ruby #{File.expand_path(__FILE__)}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;改成&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rvm-auto-ruby #{File.expand_path(__FILE__.shellescape)} # __FILE__后面加了 .shellescape
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样，就解决了这个问题。&lt;/p&gt;

&lt;p&gt;原文链接：&lt;a href="https://chriszou.com/2021/05/03/bitbar-ruby-script-gem-shellwords/" rel="nofollow" target="_blank"&gt;https://chriszou.com/2021/05/03/bitbar-ruby-script-gem-shellwords/&lt;/a&gt;&lt;/p&gt;</description>
      <author>chriszou</author>
      <pubDate>Mon, 03 May 2021 17:45:38 +0800</pubDate>
      <link>https://ruby-china.org/topics/41229</link>
      <guid>https://ruby-china.org/topics/41229</guid>
    </item>
    <item>
      <title>Rails 6.1 升级记录</title>
      <description>&lt;p&gt;时隔一年半，期待已久的 Rails 6.1 终于发布了。趁着双休，给 &lt;a href="https://github.com/ChrisZou/geekweibo" rel="nofollow" target="_blank" title=""&gt;GeekWeibo&lt;/a&gt; 从 Rails6.0 升级到了 6.1。
升级主要有三步。&lt;/p&gt;
&lt;h2 id="一、升级Gemfile里面各个gem的版本"&gt;一、升级 Gemfile 里面各个 gem 的版本&lt;/h2&gt;
&lt;p&gt;为了避免一些 gem 版本的不兼容，我先本地&lt;code&gt;gem install rails&lt;/code&gt;把系统的 rails 版本升级到 6.1。然后使用 &lt;code&gt;rails new demo61&lt;/code&gt; 创建了一个新 app 叫 demo61。接着对比 demo61/Gemfile 和 geekweibo/Gemfile 里面各个 gem 的版本号，相应的升级一下版本号。主要 diff 如下：
&lt;img src="https://images4blogs.oss-cn-hangzhou.aliyuncs.com/NvOr8T.png" title="" alt="NvOr8T"&gt;&lt;/p&gt;

&lt;p&gt;然后执行 &lt;code&gt;bundle update&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id="二、执行 rails app:update"&gt;二、执行 rails app:update&lt;/h2&gt;
&lt;p&gt;前几天才知道原来还有 &lt;code&gt;rails app:update&lt;/code&gt;这个命令，用于 app 升级。执行一下，按照提示，相应的覆盖或忽略一些文件更新。执行完了之后，很多 bin 文件和 config 文件都更新了。同时会生成两个新的 active_storage 的 migration file。一个是给 &lt;code&gt;active_storage_blobs&lt;/code&gt; table 新增了一个 &lt;code&gt;service_name&lt;/code&gt; column：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# This migration comes from active_storage (originally 20190112182829)
class AddServiceNameToActiveStorageBlobs &amp;lt; ActiveRecord::Migration[6.0]
  def up
    unless column_exists?(:active_storage_blobs, :service_name)
      add_column :active_storage_blobs, :service_name, :string

      if configured_service = ActiveStorage::Blob.service.name
        ActiveStorage::Blob.unscoped.update_all(service_name: configured_service)
      end

      change_column :active_storage_blobs, :service_name, :string, null: false
    end
  end

  def down
    remove_column :active_storage_blobs, :service_name
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;另外一个是新增了一个&lt;code&gt;active_storage_variant_records&lt;/code&gt; table&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# This migration comes from active_storage (originally 20191206030411)
class CreateActiveStorageVariantRecords &amp;lt; ActiveRecord::Migration[6.0]
  def change
    create_table :active_storage_variant_records do |t|
      t.belongs_to :blob, null: false, index: false, type: :uuid
      t.string :variation_digest, null: false

      t.index %i[ blob_id variation_digest ], name: "index_active_storage_variant_records_uniqueness", unique: true
      t.foreign_key :active_storage_blobs, column: :blob_id
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;接着执行 &lt;code&gt;rails db:migrate&lt;/code&gt;，一切正常。&lt;/p&gt;
&lt;h2 id="三、使用systemd管理puma进程"&gt;三、使用 systemd 管理 puma 进程&lt;/h2&gt;
&lt;p&gt;我的项目是使用 capistrano 来部署的。执行完前面的两个步骤，本地试运行，解决掉一个 gem 的兼容性问题（后面会提到）之后。执行&lt;code&gt;cap production deploy&lt;/code&gt;之后，提示没有 &lt;code&gt;cap production puma:restart&lt;/code&gt;这个 task。一番 google 之后，发现原来是 puma 5 把 daemon 启动模式去掉了。相应的 capistrano3-puma 5.0 之后的版本，默认的 task 里面也自然没有这个启动模式了。
解决办法是使用&lt;a href="https://en.wikipedia.org/wiki/Systemd" rel="nofollow" target="_blank" title=""&gt;systemd&lt;/a&gt;、&lt;a href="https://mmonit.com/monit/" rel="nofollow" target="_blank" title=""&gt;monit&lt;/a&gt;、&lt;a href="https://pm2.keymetrics.io/" rel="nofollow" target="_blank" title=""&gt;pm2&lt;/a&gt;这些第三方的 process monitor/manager。我因为不想折腾，所以采用linux（或者说ubuntu）自带的systemd。&lt;/p&gt;

&lt;p&gt;在 Capfile 里面新增一行&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# 在install_plugin Capistrano::Puma 之后
install_plugin Capistrano::Puma::Systemd
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后执行&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cap puma:systemd:config    # 会生成一个systemd unit文件，并上传到服务器的/etc/systemd/system/文件夹下面。
cap puma:systemd:enable    # Enable上一步上传的service
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后再执行 &lt;code&gt;cap production puma:restart&lt;/code&gt;，这个命令会在服务器上面会执行&lt;code&gt;sudo systemctl restart puma&lt;/code&gt;这时候提示报错了，说 systemd 的 service unit 里面，ExecStart 的命令格式有问题。我查看了一下，发现生成的 unit 文件里面，ExecStart 这一行的内容是&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ExecStart=~/.rvm/bin/rvm default do bundle exec puma -C /your/deploy/path/geekweibo/shared/puma.rb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我猜测是&lt;code&gt;~/&lt;/code&gt;这个地方出错了。改成绝对路径&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ExecStart=/home/username/.rvm/bin/rvm default do bundle exec puma -C /your/deploy/path/geekweibo/shared/puma.rb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后在服务器上面执行 &lt;code&gt;sudo systemctl daemon-reload&lt;/code&gt;，因为我们修改了 unit 文件，需要 reload 一下 systemd daemon 生效。&lt;/p&gt;

&lt;p&gt;回到开发机，再次执行&lt;code&gt;cap production puma:restart&lt;/code&gt;，果然就可以了。我猜测之所以 &lt;code&gt;~/&lt;/code&gt;这种写法会有问题，是因为我没有指定 puma 的 user。&lt;/p&gt;
&lt;h2 id="遇到的问题"&gt;遇到的问题&lt;/h2&gt;
&lt;p&gt;不少朋友说升级 6.1 之后，遇到很多 gem 不兼容的情况。可能是因为我这个项目比较小，我这次升级，只遇到一个 gem 不兼容。那就是&lt;a href="https://github.com/skylightio/skylight-ruby" rel="nofollow" target="_blank" title=""&gt;skylight-ruby&lt;/a&gt; gem（一个 APM 服务）。报了一个&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NoMethodError (undefined method `instrument' for #&amp;lt;ActionView::TemplateRenderer:0x00007f9d9cc61ee8&amp;gt;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样的错。这个 gem 的&lt;a href="https://github.com/skylightio/skylight-ruby/issues/163" rel="nofollow" target="_blank" title=""&gt;Github issues&lt;/a&gt;里面也有不少人反映这个问题。据作者说，gem 新版 beta 里面已经解决了，不过我不想采坑，所以没上 beta，只是按照他们的说明，用了一个 workaround，在 config/application.rb 里面加一行&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;config.skylight.probes -= %w[action_view]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;解决了问题。&lt;/p&gt;
&lt;h2 id="升级以后，有了哪些好处呢？"&gt;升级以后，有了哪些好处呢？&lt;/h2&gt;
&lt;p&gt;好像没发现。Rails 6.1 很多新增功能是针对 multiple DB 的，对我好像没什么影响。我主要是冲着 strict loading 和 activestorage 的 permanent url 来的。其中 strict loading，在另外的一个小 app 里面开了 strict loading by default，结果带来一些问题，于是又禁用了。而 activestorage 的 permanent url，除了方法名使用 &lt;code&gt;url&lt;/code&gt; 代替 &lt;code&gt;service_url&lt;/code&gt;，其他好像也没发现什么区别。我原来使用 &lt;code&gt;service_url&lt;/code&gt; 获取到的 url，貌似也不会变？不清楚是不是我理解还不到位。&lt;/p&gt;

&lt;p&gt;总体来说，因为项目比较小，这次升级还是比较顺利的，但好像也没带来什么特别的优势。所以，对于想升级的朋友，可以参考一下。&lt;/p&gt;</description>
      <author>chriszou</author>
      <pubDate>Tue, 15 Dec 2020 13:37:26 +0800</pubDate>
      <link>https://ruby-china.org/topics/40702</link>
      <guid>https://ruby-china.org/topics/40702</guid>
    </item>
    <item>
      <title>使用 Vue 前端、Rails 后端实现图片上传的功能</title>
      <description>&lt;p&gt;这两周给自己的开源项目&lt;a href="https://geekweibo.com" rel="nofollow" target="_blank" title=""&gt;极客微博&lt;/a&gt;加上了发微博带图片的功能（作为一个“微博”app，怎么能没有发图片微博的功能呢？）。没想到，做这个小功能的折腾程度，超出了我的预期。&lt;/p&gt;

&lt;p&gt;其实如果是纯 Rails MVC，那么给微博加上图片功能，简直不要太简单。后端两行核心代码：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# tweet.rb&lt;/span&gt;
&lt;span class="n"&gt;has_many_attached&lt;/span&gt; &lt;span class="ss"&gt;:images&lt;/span&gt;
&lt;span class="err"&gt;​&lt;/span&gt;
&lt;span class="c1"&gt;# tweet_controller.rb&lt;/span&gt;
&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:tweet&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;permit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;images: &lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后前端相关的 template 文件里面，相应的加上文件选择控件，和显示图片的相关代码就搞定了，毕竟&lt;a href="https://edgeguides.rubyonrails.org/active_storage_overview.html" rel="nofollow" target="_blank" title=""&gt;ActiveStorage&lt;/a&gt;什么都帮你做好了。&lt;/p&gt;

&lt;p&gt;可是极客微博前端用了 Vue。发微博的时候，是通过前端发 POST Ajax 请求的方式发的，所以事情就变得复杂了。首先，你没有办法像文本字段一样，给 json body 加一个 file 字段，然后 POST 给后端。所以想要在前端用 Ajax 发请求上传图片，就剩下两种办法：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;在前端先把图片上传到图片存储服务（我用的是阿里云 OSS），拿到上传后的图片 url，然后把 url 传给后端。&lt;/li&gt;
&lt;li&gt;使用 FormData。这是经过一些搜索，以及在微信群里面请教后，得到的方案。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;我不是特别想使用第一种方式，原因有多个。其一，这种方式的实现成本不小，这个可以在 Rails ActiveStorage 的&lt;a href="https://edgeguides.rubyonrails.org/active_storage_overview.html#direct-uploads" rel="nofollow" target="_blank" title=""&gt;官方文档&lt;/a&gt;里面了解到。其二，这种方式的用户体验也不是很好，因为上传需要一个过程，如果上传的图片比较大的话，用户等待的时间就会有点长。先压缩再上传？那又增加了一点工作量。最后，如果用户想换一张图片的话，那之前的上传和等待就都浪费了。出于这几点考虑，我决定使用第二种方式。&lt;/p&gt;

&lt;p&gt;但是使用 FormData，其实就相当于使用表单提交的方式发请求。出于安全考虑，为了防止 CSRF 攻击，Rails 默认需要验证表单提交的请求的 CSRF token。在使用 form_for, form_with 这些 rails view helper 构造表单的时候，rails 会自动生成 csrf tag field，然后在表单提交的时候，自动带上这个 field。然而现在，我们的表单是自己构造的（记住这里，后面要考），不是使用 Rails 的 view helper 生成的：&lt;/p&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;enctype=&lt;/span&gt;&lt;span class="s"&gt;"multipart/form-data"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;textarea&lt;/span&gt; &lt;span class="na"&gt;v-model=&lt;/span&gt;&lt;span class="s"&gt;"new_tweet_body"&lt;/span&gt;
  &lt;span class="err"&gt;...&lt;/span&gt;
  &lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="na"&gt;input&lt;/span&gt; &lt;span class="na"&gt;ref=&lt;/span&gt;&lt;span class="s"&gt;"image_picker"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"file"&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;user1=&lt;/span&gt;&lt;span class="s"&gt;"onFileChange"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  ...
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;user2=&lt;/span&gt;&lt;span class="s"&gt;"postTweet"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;发布&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们不能在这个 form 里面自己随便生成一个 csrf token field，然后带给后端，因为这样生成的 token 是无效的。token 必须由后端生成，然后通过某种方式传给前端发 Ajax 请求的地方。这个怎么办呢？
Google 一下，发现了&lt;a href="https://gist.github.com/przbadu/084197ea821a98b0e177b266b41ba0a2" rel="nofollow" target="_blank" title=""&gt;这篇文章&lt;/a&gt;。看了下，解决方法其实非常简单。那就是在 layout 文件（比如 application.html.erb) 的 header 区加一行：&lt;/p&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;csrf_meta_tags&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这会生成一个&lt;/p&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"csrf-token"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"the-secret-token-value"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样的 tag。里面的&lt;code&gt;content&lt;/code&gt; 就是我们想要的 token。然后在发 Ajax 请求的地方，直接用 JS 获得这个值，加到 Key 为'X-CSRF-Token'的 header 里面去就好了：&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;csrfToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;meta[name="csrf-token"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/tweets&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;X-CSRF-Token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;csrfToken&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;})...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样，CSRF Token 的问题就解决了。&lt;/p&gt;

&lt;p&gt;上面提到的过程，其实还有一个坑。那就是我们构造了一个 form，然后把发微博相关的输入控件（textarea/file input/button等）都放在这个form里面。这样一来，每次点击发布按钮，页面就会刷新一次，然后网络请求的callback也不会得到调用。这一方面导致用户体验不好（页面刷新），另外一方面也导致我在success callback 里面做的一些清理工作没办法得到执行。
刚开始我以为是这个页面刷新是后端的返回导致的，折腾了半天，才发现不是，而是由于前端存在 form 的原因。其实这个 form 完全是没必要的，去掉以后，页面刷新的问题就解决了，callback 也能正确的到回调。&lt;/p&gt;

&lt;p&gt;这个功能完整的代码可以在&lt;a href="https://github.com/ChrisZou/geekweibo" rel="nofollow" target="_blank" title=""&gt;github&lt;/a&gt;上面看到，这里把前端主要代码贴一下，供有类似需求的小伙伴参考。后端的代码跟前面提到的一样，只需要两行改动而已。&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;postTweet&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;//...&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;formData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FormData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tweet[body]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;new_tweet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;// this.imageFile是通过 file input上传的那个文件。&lt;/span&gt;
  &lt;span class="c1"&gt;// 注意key后面的"[]"因为images是个数组。&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;imageFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tweet[images][]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;imageFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;csrfToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;meta[name="csrf-token"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/tweets&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;X-CSRF-Token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;csrfToken&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="c1"&gt;//clear local cache&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;</description>
      <author>chriszou</author>
      <pubDate>Thu, 19 Nov 2020 22:11:04 +0800</pubDate>
      <link>https://ruby-china.org/topics/40594</link>
      <guid>https://ruby-china.org/topics/40594</guid>
    </item>
    <item>
      <title>个人 Rails + Vue 开源项目：一个 Focus 在技术领域的微博 -- “极客微博”</title>
      <description>&lt;p&gt;先放上地址~
项目地址：&lt;a href="https://geekweibo.com/" rel="nofollow" target="_blank" title=""&gt;极客微博&lt;/a&gt; 欢迎体验、吐槽、反馈
Github 地址：&lt;a href="https://github.com/ChrisZou/geekweibo" rel="nofollow" target="_blank" title=""&gt;ChrisZou/geekweibo&lt;/a&gt; 欢迎 star、fork、pr、issues&lt;/p&gt;

&lt;p&gt;用到的技术栈&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ruby on Rails

&lt;ul&gt;
&lt;li&gt;Ruby 2.7.1, Rails 6.0.3.2&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;VueJS, AlphineJS&lt;/li&gt;
&lt;li&gt;TailwindCSS&lt;/li&gt;
&lt;li&gt;PostgreSQL&lt;/li&gt;
&lt;li&gt;ElasticSearch&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;如题所说，这是一个类似于 Twitter 的项目。目前还是 WIP，有一些最基本的功能：发推文、搜索、评论、点赞、通知等。&lt;br&gt;
之所以做这个项目，主要是出于，想要有个地方能够便捷的存放一些零碎知识片段 + 简单的分享、发现的功能。由于没有找到合适的产品，所以自己做了一个。如果还是好奇的话，可以看看&lt;a href="https://chriszou.com/2020/10/17/introducing-geekweibo/" rel="nofollow" target="_blank" title=""&gt;这篇文章&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;由于我的本职工作是客户端开发（Android），Ruby/Rails 虽然接触时间不短了，也一直处于初学者的阶段，希望大家不吝指教！&lt;/p&gt;</description>
      <author>chriszou</author>
      <pubDate>Sat, 17 Oct 2020 21:27:44 +0800</pubDate>
      <link>https://ruby-china.org/topics/40487</link>
      <guid>https://ruby-china.org/topics/40487</guid>
    </item>
    <item>
      <title>Mac 安装 pg gem 失败，提示 “make: /usr/local/Cellar/coreutils/8.30/bin/gmkdir: No such file or directory”。</title>
      <description>&lt;p&gt;我本地是安装了 coreutils 8.31 的&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; /usr/local/Cellar/coreutils/
8.31
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不知道为什么在编译 native extension 的时候，好像代码里面写死了 8.30 版本。
完整的错误提示：&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;gem &lt;span class="nb"&gt;install &lt;/span&gt;pg
Building native extensions. This could take a &lt;span class="k"&gt;while&lt;/span&gt;...
ERROR:  Error installing pg:
    ERROR: Failed to build gem native extension.

    current directory: /Users/chris/.rvm/gems/ruby-2.6.0/gems/pg-1.1.4/ext
/Users/chris/.rvm/rubies/ruby-2.6.0/bin/ruby &lt;span class="nt"&gt;-I&lt;/span&gt; /Users/chris/.rvm/rubies/ruby-2.6.0/lib/ruby/2.6.0 &lt;span class="nt"&gt;-r&lt;/span&gt; ./siteconf20190512-93337-1jm5hew.rb extconf.rb
checking &lt;span class="k"&gt;for &lt;/span&gt;pg_config... &lt;span class="nb"&gt;yes
&lt;/span&gt;Using config values from /usr/local/bin/pg_config
checking &lt;span class="k"&gt;for &lt;/span&gt;libpq-fe.h... &lt;span class="nb"&gt;yes
&lt;/span&gt;checking &lt;span class="k"&gt;for &lt;/span&gt;libpq/libpq-fs.h... &lt;span class="nb"&gt;yes
&lt;/span&gt;checking &lt;span class="k"&gt;for &lt;/span&gt;pg_config_manual.h... &lt;span class="nb"&gt;yes
&lt;/span&gt;checking &lt;span class="k"&gt;for &lt;/span&gt;PQconnectdb&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nt"&gt;-lpq&lt;/span&gt;... &lt;span class="nb"&gt;yes
&lt;/span&gt;checking &lt;span class="k"&gt;for &lt;/span&gt;PQsetSingleRowMode&lt;span class="o"&gt;()&lt;/span&gt;... &lt;span class="nb"&gt;yes
&lt;/span&gt;checking &lt;span class="k"&gt;for &lt;/span&gt;PQconninfo&lt;span class="o"&gt;()&lt;/span&gt;... &lt;span class="nb"&gt;yes
&lt;/span&gt;checking &lt;span class="k"&gt;for &lt;/span&gt;PQsslAttribute&lt;span class="o"&gt;()&lt;/span&gt;... &lt;span class="nb"&gt;yes
&lt;/span&gt;checking &lt;span class="k"&gt;for &lt;/span&gt;PQencryptPasswordConn&lt;span class="o"&gt;()&lt;/span&gt;... &lt;span class="nb"&gt;yes
&lt;/span&gt;checking &lt;span class="k"&gt;for &lt;/span&gt;timegm&lt;span class="o"&gt;()&lt;/span&gt;... &lt;span class="nb"&gt;yes
&lt;/span&gt;checking &lt;span class="k"&gt;for &lt;/span&gt;rb_gc_adjust_memory_usage&lt;span class="o"&gt;()&lt;/span&gt;... &lt;span class="nb"&gt;yes
&lt;/span&gt;checking &lt;span class="k"&gt;for &lt;/span&gt;PG_DIAG_TABLE_NAME &lt;span class="k"&gt;in &lt;/span&gt;libpq-fe.h... &lt;span class="nb"&gt;yes
&lt;/span&gt;checking &lt;span class="k"&gt;for &lt;/span&gt;unistd.h... &lt;span class="nb"&gt;yes
&lt;/span&gt;checking &lt;span class="k"&gt;for &lt;/span&gt;inttypes.h... &lt;span class="nb"&gt;yes
&lt;/span&gt;checking &lt;span class="k"&gt;for &lt;/span&gt;C99 variable length arrays... &lt;span class="nb"&gt;yes
&lt;/span&gt;creating extconf.h
creating Makefile

current directory: /Users/chris/.rvm/gems/ruby-2.6.0/gems/pg-1.1.4/ext
make &lt;span class="s2"&gt;"DESTDIR="&lt;/span&gt; clean

current directory: /Users/chris/.rvm/gems/ruby-2.6.0/gems/pg-1.1.4/ext
make &lt;span class="s2"&gt;"DESTDIR="&lt;/span&gt;
compiling gvl_wrappers.c
compiling pg.c
compiling pg_binary_decoder.c
compiling pg_binary_encoder.c
compiling pg_coder.c
pg_coder.c:206:34: warning: implicit conversion loses integer precision: &lt;span class="s1"&gt;'long'&lt;/span&gt; to &lt;span class="s1"&gt;'int'&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;-Wshorten-64-to-32&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
        res &lt;span class="o"&gt;=&lt;/span&gt; this-&amp;gt;dec_func&lt;span class="o"&gt;(&lt;/span&gt;this, val, RSTRING_LEN&lt;span class="o"&gt;(&lt;/span&gt;argv[0]&lt;span class="o"&gt;)&lt;/span&gt;, tuple, field, ENCODING_GET&lt;span class="o"&gt;(&lt;/span&gt;argv[0]&lt;span class="o"&gt;))&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
              ~~~~                      ^~~~~~~~~~~~~~~~~~~~
/Users/chris/.rvm/rubies/ruby-2.6.0/include/ruby-2.6.0/ruby/ruby.h:1000:6: note: expanded from macro &lt;span class="s1"&gt;'RSTRING_LEN'&lt;/span&gt;
     RSTRING_EMBED_LEN&lt;span class="o"&gt;(&lt;/span&gt;str&lt;span class="o"&gt;)&lt;/span&gt; : &lt;span class="se"&gt;\&lt;/span&gt;
     ^~~~~~~~~~~~~~~~~~~~~~
/Users/chris/.rvm/rubies/ruby-2.6.0/include/ruby-2.6.0/ruby/ruby.h:996:6: note: expanded from macro &lt;span class="s1"&gt;'RSTRING_EMBED_LEN'&lt;/span&gt;
     &lt;span class="o"&gt;(&lt;/span&gt;long&lt;span class="o"&gt;)((&lt;/span&gt;RBASIC&lt;span class="o"&gt;(&lt;/span&gt;str&lt;span class="o"&gt;)&lt;/span&gt;-&amp;gt;flags &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; RSTRING_EMBED_LEN_SHIFT&lt;span class="o"&gt;)&lt;/span&gt; &amp;amp; &lt;span class="se"&gt;\&lt;/span&gt;
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
pg_coder.c:206:34: warning: implicit conversion loses integer precision: &lt;span class="s1"&gt;'long'&lt;/span&gt; to &lt;span class="s1"&gt;'int'&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;-Wshorten-64-to-32&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
        res &lt;span class="o"&gt;=&lt;/span&gt; this-&amp;gt;dec_func&lt;span class="o"&gt;(&lt;/span&gt;this, val, RSTRING_LEN&lt;span class="o"&gt;(&lt;/span&gt;argv[0]&lt;span class="o"&gt;)&lt;/span&gt;, tuple, field, ENCODING_GET&lt;span class="o"&gt;(&lt;/span&gt;argv[0]&lt;span class="o"&gt;))&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
              ~~~~                      ^~~~~~~~~~~~~~~~~~~~
/Users/chris/.rvm/rubies/ruby-2.6.0/include/ruby-2.6.0/ruby/ruby.h:1001:28: note: expanded from macro &lt;span class="s1"&gt;'RSTRING_LEN'&lt;/span&gt;
     RSTRING&lt;span class="o"&gt;(&lt;/span&gt;str&lt;span class="o"&gt;)&lt;/span&gt;-&amp;gt;as.heap.len&lt;span class="o"&gt;)&lt;/span&gt;
     ~~~~~~~~~~~~~~~~~~~~~~^~~
2 warnings generated.
compiling pg_connection.c
compiling pg_copy_coder.c
pg_copy_coder.c:225:15: warning: implicit conversion loses integer precision: &lt;span class="s1"&gt;'long'&lt;/span&gt; to &lt;span class="s1"&gt;'int'&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;-Wshorten-64-to-32&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
                                        strlen &lt;span class="o"&gt;=&lt;/span&gt; RSTRING_LEN&lt;span class="o"&gt;(&lt;/span&gt;subint&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                                               ~ ^~~~~~~~~~~~~~~~~~~
/Users/chris/.rvm/rubies/ruby-2.6.0/include/ruby-2.6.0/ruby/ruby.h:1000:6: note: expanded from macro &lt;span class="s1"&gt;'RSTRING_LEN'&lt;/span&gt;
     RSTRING_EMBED_LEN&lt;span class="o"&gt;(&lt;/span&gt;str&lt;span class="o"&gt;)&lt;/span&gt; : &lt;span class="se"&gt;\&lt;/span&gt;
     ^~~~~~~~~~~~~~~~~~~~~~
/Users/chris/.rvm/rubies/ruby-2.6.0/include/ruby-2.6.0/ruby/ruby.h:996:6: note: expanded from macro &lt;span class="s1"&gt;'RSTRING_EMBED_LEN'&lt;/span&gt;
     &lt;span class="o"&gt;(&lt;/span&gt;long&lt;span class="o"&gt;)((&lt;/span&gt;RBASIC&lt;span class="o"&gt;(&lt;/span&gt;str&lt;span class="o"&gt;)&lt;/span&gt;-&amp;gt;flags &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; RSTRING_EMBED_LEN_SHIFT&lt;span class="o"&gt;)&lt;/span&gt; &amp;amp; &lt;span class="se"&gt;\&lt;/span&gt;
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
pg_copy_coder.c:225:15: warning: implicit conversion loses integer precision: &lt;span class="s1"&gt;'long'&lt;/span&gt; to &lt;span class="s1"&gt;'int'&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;-Wshorten-64-to-32&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
                                        strlen &lt;span class="o"&gt;=&lt;/span&gt; RSTRING_LEN&lt;span class="o"&gt;(&lt;/span&gt;subint&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                                               ~ ^~~~~~~~~~~~~~~~~~~
/Users/chris/.rvm/rubies/ruby-2.6.0/include/ruby-2.6.0/ruby/ruby.h:1001:28: note: expanded from macro &lt;span class="s1"&gt;'RSTRING_LEN'&lt;/span&gt;
     RSTRING&lt;span class="o"&gt;(&lt;/span&gt;str&lt;span class="o"&gt;)&lt;/span&gt;-&amp;gt;as.heap.len&lt;span class="o"&gt;)&lt;/span&gt;
     ~~~~~~~~~~~~~~~~~~~~~~^~~
pg_copy_coder.c:531:23: warning: implicit conversion loses integer precision: &lt;span class="s1"&gt;'long'&lt;/span&gt; to &lt;span class="s1"&gt;'int'&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;-Wshorten-64-to-32&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
                input_len &lt;span class="o"&gt;=&lt;/span&gt; end_ptr - start_ptr&lt;span class="p"&gt;;&lt;/span&gt;
                          ~ ~~~~~~~~^~~~~~~~~~~
3 warnings generated.
compiling pg_errors.c
compiling pg_result.c
compiling pg_text_decoder.c
compiling pg_text_encoder.c
pg_text_encoder.c:170:14: warning: implicit conversion loses integer precision: &lt;span class="s1"&gt;'long'&lt;/span&gt; to &lt;span class="s1"&gt;'int'&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;-Wshorten-64-to-32&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
                        len &lt;span class="o"&gt;=&lt;/span&gt; out - start&lt;span class="p"&gt;;&lt;/span&gt;
                            ~ ~~~~^~~~~~~
pg_text_encoder.c:289:15: warning: implicit conversion loses integer precision: &lt;span class="s1"&gt;'long'&lt;/span&gt; to &lt;span class="s1"&gt;'int'&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;-Wshorten-64-to-32&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
                &lt;span class="k"&gt;return &lt;/span&gt;optr - out&lt;span class="p"&gt;;&lt;/span&gt;
                ~~~~~~ ~~~~~^~~~~
pg_text_encoder.c:293:12: warning: implicit conversion loses integer precision: &lt;span class="s1"&gt;'long'&lt;/span&gt; to &lt;span class="s1"&gt;'int'&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;-Wshorten-64-to-32&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
                &lt;span class="k"&gt;return &lt;/span&gt;2 + RSTRING_LEN&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;intermediate&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; 2&lt;span class="p"&gt;;&lt;/span&gt;
                ~~~~~~ ~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
pg_text_encoder.c:500:13: warning: implicit conversion loses integer precision: &lt;span class="s1"&gt;'long'&lt;/span&gt; to &lt;span class="s1"&gt;'int'&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;-Wshorten-64-to-32&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
        nr_elems &lt;span class="o"&gt;=&lt;/span&gt; RARRAY_LEN&lt;span class="o"&gt;(&lt;/span&gt;value&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                 ~ ^~~~~~~~~~~~~~~~~
/Users/chris/.rvm/rubies/ruby-2.6.0/include/ruby-2.6.0/ruby/ruby.h:1058:23: note: expanded from macro &lt;span class="s1"&gt;'RARRAY_LEN'&lt;/span&gt;
&lt;span class="c"&gt;#define RARRAY_LEN(a) rb_array_len(a)&lt;/span&gt;
                      ^~~~~~~~~~~~~~~
4 warnings generated.
compiling pg_tuple.c
pg_tuple.c:475:15: warning: implicit conversion loses integer precision: &lt;span class="s1"&gt;'long'&lt;/span&gt; to &lt;span class="s1"&gt;'int'&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;-Wshorten-64-to-32&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
        num_fields &lt;span class="o"&gt;=&lt;/span&gt; RARRAY_LEN&lt;span class="o"&gt;(&lt;/span&gt;values&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                   ~ ^~~~~~~~~~~~~~~~~~
/Users/chris/.rvm/rubies/ruby-2.6.0/include/ruby-2.6.0/ruby/ruby.h:1058:23: note: expanded from macro &lt;span class="s1"&gt;'RARRAY_LEN'&lt;/span&gt;
&lt;span class="c"&gt;#define RARRAY_LEN(a) rb_array_len(a)&lt;/span&gt;
                      ^~~~~~~~~~~~~~~
1 warning generated.
compiling pg_type_map.c
compiling pg_type_map_all_strings.c
compiling pg_type_map_by_class.c
compiling pg_type_map_by_column.c
pg_type_map_by_column.c:161:52: warning: implicit conversion loses integer precision: &lt;span class="s1"&gt;'long'&lt;/span&gt; to &lt;span class="s1"&gt;'int'&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;-Wshorten-64-to-32&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;return &lt;/span&gt;dec_func&lt;span class="o"&gt;(&lt;/span&gt; p_coder, RSTRING_PTR&lt;span class="o"&gt;(&lt;/span&gt;field_str&lt;span class="o"&gt;)&lt;/span&gt;, RSTRING_LEN&lt;span class="o"&gt;(&lt;/span&gt;field_str&lt;span class="o"&gt;)&lt;/span&gt;, 0, fieldno, enc_idx &lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
               ~~~~~~~~                                   ^~~~~~~~~~~~~~~~~~~~~~
/Users/chris/.rvm/rubies/ruby-2.6.0/include/ruby-2.6.0/ruby/ruby.h:1000:6: note: expanded from macro &lt;span class="s1"&gt;'RSTRING_LEN'&lt;/span&gt;
     RSTRING_EMBED_LEN&lt;span class="o"&gt;(&lt;/span&gt;str&lt;span class="o"&gt;)&lt;/span&gt; : &lt;span class="se"&gt;\&lt;/span&gt;
     ^~~~~~~~~~~~~~~~~~~~~~
/Users/chris/.rvm/rubies/ruby-2.6.0/include/ruby-2.6.0/ruby/ruby.h:996:6: note: expanded from macro &lt;span class="s1"&gt;'RSTRING_EMBED_LEN'&lt;/span&gt;
     &lt;span class="o"&gt;(&lt;/span&gt;long&lt;span class="o"&gt;)((&lt;/span&gt;RBASIC&lt;span class="o"&gt;(&lt;/span&gt;str&lt;span class="o"&gt;)&lt;/span&gt;-&amp;gt;flags &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; RSTRING_EMBED_LEN_SHIFT&lt;span class="o"&gt;)&lt;/span&gt; &amp;amp; &lt;span class="se"&gt;\&lt;/span&gt;
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
pg_type_map_by_column.c:161:52: warning: implicit conversion loses integer precision: &lt;span class="s1"&gt;'long'&lt;/span&gt; to &lt;span class="s1"&gt;'int'&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;-Wshorten-64-to-32&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;return &lt;/span&gt;dec_func&lt;span class="o"&gt;(&lt;/span&gt; p_coder, RSTRING_PTR&lt;span class="o"&gt;(&lt;/span&gt;field_str&lt;span class="o"&gt;)&lt;/span&gt;, RSTRING_LEN&lt;span class="o"&gt;(&lt;/span&gt;field_str&lt;span class="o"&gt;)&lt;/span&gt;, 0, fieldno, enc_idx &lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
               ~~~~~~~~                                   ^~~~~~~~~~~~~~~~~~~~~~
/Users/chris/.rvm/rubies/ruby-2.6.0/include/ruby-2.6.0/ruby/ruby.h:1001:28: note: expanded from macro &lt;span class="s1"&gt;'RSTRING_LEN'&lt;/span&gt;
     RSTRING&lt;span class="o"&gt;(&lt;/span&gt;str&lt;span class="o"&gt;)&lt;/span&gt;-&amp;gt;as.heap.len&lt;span class="o"&gt;)&lt;/span&gt;
     ~~~~~~~~~~~~~~~~~~~~~~^~~
pg_type_map_by_column.c:230:17: warning: implicit conversion loses integer precision: &lt;span class="s1"&gt;'long'&lt;/span&gt; to &lt;span class="s1"&gt;'int'&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;-Wshorten-64-to-32&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
        conv_ary_len &lt;span class="o"&gt;=&lt;/span&gt; RARRAY_LEN&lt;span class="o"&gt;(&lt;/span&gt;conv_ary&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                     ~ ^~~~~~~~~~~~~~~~~~~~
/Users/chris/.rvm/rubies/ruby-2.6.0/include/ruby-2.6.0/ruby/ruby.h:1058:23: note: expanded from macro &lt;span class="s1"&gt;'RARRAY_LEN'&lt;/span&gt;
&lt;span class="c"&gt;#define RARRAY_LEN(a) rb_array_len(a)&lt;/span&gt;
                      ^~~~~~~~~~~~~~~
3 warnings generated.
compiling pg_type_map_by_mri_type.c
compiling pg_type_map_by_oid.c
compiling pg_type_map_in_ruby.c
compiling util.c
util.c:119:24: warning: implicit conversion loses integer precision: &lt;span class="s1"&gt;'long'&lt;/span&gt; to &lt;span class="s1"&gt;'int'&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;-Wshorten-64-to-32&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;char&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;out_ptr - out&lt;span class="p"&gt;;&lt;/span&gt;
        ~~~~~~ ~~~~~~~~~~~~~~~^~~~~
1 warning generated.
linking shared-object pg_ext.bundle

current directory: /Users/chris/.rvm/gems/ruby-2.6.0/gems/pg-1.1.4/ext
make &lt;span class="s2"&gt;"DESTDIR="&lt;/span&gt; &lt;span class="nb"&gt;install
&lt;/span&gt;make: /usr/local/Cellar/coreutils/8.30/bin/gmkdir: No such file or directory
make: &lt;span class="k"&gt;***&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;.sitearchdir.time] Error 1

make &lt;span class="nb"&gt;install &lt;/span&gt;failed, &lt;span class="nb"&gt;exit &lt;/span&gt;code 2

Gem files will remain installed &lt;span class="k"&gt;in&lt;/span&gt; /Users/chris/.rvm/gems/ruby-2.6.0/gems/pg-1.1.4 &lt;span class="k"&gt;for &lt;/span&gt;inspection.
Results logged to /Users/chris/.rvm/gems/ruby-2.6.0/extensions/x86_64-darwin-18/2.6.0/pg-1.1.4/gem_make.out

&lt;/code&gt;&lt;/pre&gt;</description>
      <author>chriszou</author>
      <pubDate>Sun, 12 May 2019 17:54:43 +0800</pubDate>
      <link>https://ruby-china.org/topics/38513</link>
      <guid>https://ruby-china.org/topics/38513</guid>
    </item>
  </channel>
</rss>
