<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>lingceng (科科巨无霸)</title>
    <link>https://ruby-china.org/lingceng</link>
    <description>less is more</description>
    <language>en-us</language>
    <item>
      <title>项目中使用 Rails7 importmap 的体验</title>
      <description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;最近用 Rails7 + hotwire + importmap 的技术站做了个 AI 站，下图中标黄的都是有较多异步交互的地方，项目中基本没有使用手动 Ajax 与 JSON 交互，仅使用 turbo_frame、turbo_stream 来完成交互。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/lingceng/413c7f28-f645-4426-aa98-37026b8fc9b4.png!large" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;这里重点说说最新的 importmap 的使用问题，也欢迎大家体验下 &lt;a href="https://www.kittyai.cn/" rel="nofollow" target="_blank" title=""&gt;kittyai.cn&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="Importmap 的基本用法"&gt;Importmap 的基本用法&lt;/h2&gt;&lt;h3 id="importmap.rb 示例"&gt;importmap.rb 示例&lt;/h3&gt;
&lt;p&gt;下面是我的 config/imortmap.rb 部分内容，前面部分是脚手架生成的 hotwire 等库的配置。&lt;/p&gt;

&lt;p&gt;这里 controller 目录里的文件是可以&lt;strong&gt;动态加载&lt;/strong&gt;的，例如 HTML 中有某个 data-controller="message"，才会加载 message_controller.js 文件。&lt;/p&gt;

&lt;p&gt;额外引入了 highlight.js 的高亮配置，注意 importmap 是可以&lt;strong&gt;配置目录&lt;/strong&gt;的。这里也发挥了其按需加载的优势，用到什么语言才加载什么语言的高亮代码。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Pin npm packages by running ./bin/importmap&lt;/span&gt;

&lt;span class="n"&gt;pin&lt;/span&gt; &lt;span class="s2"&gt;"application"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;preload: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;
&lt;span class="n"&gt;pin&lt;/span&gt; &lt;span class="s2"&gt;"@hotwired/turbo-rails"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;to: &lt;/span&gt;&lt;span class="s2"&gt;"turbo.min.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;preload: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;
&lt;span class="n"&gt;pin&lt;/span&gt; &lt;span class="s2"&gt;"@hotwired/stimulus"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;to: &lt;/span&gt;&lt;span class="s2"&gt;"https://ga.jspm.io/npm:@hotwired/stimulus@3.2.1/dist/stimulus.js"&lt;/span&gt;
&lt;span class="n"&gt;pin&lt;/span&gt; &lt;span class="s2"&gt;"@hotwired/stimulus-loading"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;to: &lt;/span&gt;&lt;span class="s2"&gt;"stimulus-loading.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;preload: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;
&lt;span class="n"&gt;pin_all_from&lt;/span&gt; &lt;span class="s2"&gt;"app/javascript/controllers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;under: &lt;/span&gt;&lt;span class="s2"&gt;"controllers"&lt;/span&gt;
&lt;span class="n"&gt;pin_all_from&lt;/span&gt; &lt;span class="s2"&gt;"app/javascript/utils"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;under: &lt;/span&gt;&lt;span class="s2"&gt;"utils"&lt;/span&gt;

&lt;span class="c1"&gt;# For markdown preview&lt;/span&gt;
&lt;span class="c1"&gt;# https://jspm-packages.deno.dev/package/markdown-it@13.0.1&lt;/span&gt;
&lt;span class="n"&gt;pin&lt;/span&gt; &lt;span class="s2"&gt;"markdown-it"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;to: &lt;/span&gt;&lt;span class="s2"&gt;"https://ga.jspm.io/npm:markdown-it@13.0.1/dist/markdown-it.js"&lt;/span&gt;

&lt;span class="c1"&gt;# For code syntax highlight&lt;/span&gt;
&lt;span class="c1"&gt;# 这里使用了路径 import https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap&lt;/span&gt;
&lt;span class="n"&gt;pin&lt;/span&gt; &lt;span class="s2"&gt;"highlight.js/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;to: &lt;/span&gt;&lt;span class="s2"&gt;"https://ga.jspm.io/npm:highlight.js@11.9.0/"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="开启HTTPS"&gt;开启 HTTPS&lt;/h3&gt;
&lt;p&gt;另外注意需要开启 HTTP2，能提升多文件加载的效率，例如在 Nginx 要这样配置：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;server {
  listen 443 ssl http2
}
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="逻辑动态import"&gt;逻辑动态 import&lt;/h3&gt;
&lt;p&gt;除了可以通过静态的 import 来加载依赖，代码中甚至可以动态 import()，例如&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;highlight.js/lib/languages/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;language&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.js&lt;/span&gt;&lt;span class="dl"&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;module&lt;/span&gt;&lt;span class="p"&gt;)&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;hljs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;registerLanguage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;language&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;hljs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;highlightElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;codeElement&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;err&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;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;highlight error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&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;h2 id="遇到的问题"&gt;遇到的问题&lt;/h2&gt;&lt;h3 id="有些库对ES Module支持得不好"&gt;有些库对 ES Module 支持得不好&lt;/h3&gt;
&lt;p&gt;Javascript 的库一般会说用 npm install 等来安装，会依赖 window.process 里的环境变量，所以直接在 Web 端引入会报错。&lt;/p&gt;

&lt;p&gt;例如 tippy.js 这个库，我是在 HTML 中加了下面的代码来 Fix:&lt;/p&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"application/javascript"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="c1"&gt;// Fix tippy ESM bug. https://github.com/atomiks/tippyjs/issues/990&lt;/span&gt;
  &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;NODE_ENV&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="Importmap 不会管理 CSS"&gt;Importmap 不会管理 CSS&lt;/h3&gt;
&lt;p&gt;虽然 JS 可以通过 import 来动态还需加载了，写得很顺滑，但 CSS 并不会。&lt;/p&gt;

&lt;p&gt;还是 tippy.js 的例子，需要在 HTML 中额外配置 CSS 依赖&lt;/p&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://ga.jspm.io/npm:tippy.js@6.3.6/dist/tippy.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;所以要不要用 importmap 还是需要谨慎。它的优势是细粒度、动态的加载 JS，但其普及度还不是很高，所以容易遇到细节问题。如果要考虑低版本浏览器，importmap 的加载性能和引入的代码的兼容性都可能是问题。&lt;/p&gt;</description>
      <author>lingceng</author>
      <pubDate>Sun, 03 Dec 2023 18:50:26 +0800</pubDate>
      <link>https://ruby-china.org/topics/43495</link>
      <guid>https://ruby-china.org/topics/43495</guid>
    </item>
    <item>
      <title>Rails 项目连接第二个数据库小结</title>
      <description>&lt;h2 id="Rails项目连接第二个数据库小结"&gt;Rails 项目连接第二个数据库小结&lt;/h2&gt;
&lt;p&gt;业务需要，Rails 项目需要接入第二个数据库，这里记录一些适配的细节。&lt;br&gt;
环境：Rails 4.2.5 Ruby2.3.0 Mysql5.7.10&lt;/p&gt;
&lt;h3 id="不同的DB配置"&gt;不同的 DB 配置&lt;/h3&gt;
&lt;p&gt;在 config/database.yml 添加第二个数据库的配置，添加环境做后缀，这样方便测试和上线。&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;data_source_development&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nl"&gt;&amp;amp;data_default&lt;/span&gt;
  &lt;span class="na"&gt;adapter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql2&lt;/span&gt;
  &lt;span class="na"&gt;encoding&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;utf8mb4&lt;/span&gt;
  &lt;span class="na"&gt;reconnect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;data_source_development&lt;/span&gt;
  &lt;span class="na"&gt;pool&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
  &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;root&lt;/span&gt;
  &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;password&lt;/span&gt;
  &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;localhost&lt;/span&gt;

&lt;span class="na"&gt;data_source_test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*data_default&lt;/span&gt;
  &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;data_source_test&lt;/span&gt;

&lt;span class="na"&gt;data_source_production&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*data_default&lt;/span&gt;
  &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;data_source_production&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;创建一个继承自 ActiveRecord::Base 的类，设置为 abstract_class&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DataRecord&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abstract_class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
  &lt;span class="n"&gt;establish_connection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"data_source_&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_sym&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="不按约定的表名"&gt;不按约定的表名&lt;/h3&gt;
&lt;p&gt;Rails 里表名需要是类名称下划线形式的复数，我接入的第二个数据库全是单数，还有前缀。
例如 Data::Player 需要对应到 data_player 表。需要做下面的配置：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DataRecord&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abstract_class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
  &lt;span class="c1"&gt;# New added&lt;/span&gt;
  &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;table_name_prefix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"data_"&lt;/span&gt;
  &lt;span class="c1"&gt;# New added&lt;/span&gt;
  &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pluralize_table_names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;
  &lt;span class="n"&gt;establish_connection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"data_source_&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_sym&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果没有规律，可以通过&lt;code&gt;self.table_name = 'table_name'&lt;/code&gt;来设置表名。&lt;/p&gt;
&lt;h3 id="不同的updated_at或者created_at"&gt;不同的 updated_at 或者 created_at&lt;/h3&gt;
&lt;p&gt;第二个数据库不是用 updated_at 来表示更新时间，而是用 last_updated，可以通过重写下面的方法设置：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;timestamp_attributes_for_update&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:last_updated&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;创建时间用 timestamp_attributes_for_create&lt;/p&gt;
&lt;h3 id="存储的时间使用不同的时区"&gt;存储的时间使用不同的时区&lt;/h3&gt;
&lt;p&gt;Rails 在存储和获取 datatime 时会根据配置做转换，当前的配置是存储 utc，显示北京时区。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time_zone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Beijing'&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;active_record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;default_timezone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:utc&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;第二个数据库存储的是北京时间，所以需要处理第二个数据库的时区转换。
Rails 不能对时区做局部配置，所以处理麻烦一些，我使用的是在写入时 +8，读取时 -8。例如&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;start_time&lt;/span&gt;
  &lt;span class="n"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'start_time'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'start_time'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hour&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;start_time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;converted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;present?&lt;/span&gt;
                 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_a?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="no"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hour&lt;/span&gt;
               &lt;span class="k"&gt;else&lt;/span&gt;
                 &lt;span class="n"&gt;value&lt;/span&gt;
               &lt;span class="k"&gt;end&lt;/span&gt;
   &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kp"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;converted&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当然这样每一个 model 重写有点麻烦，所以用了个&lt;a href="https://gist.github.com/lingceng/2bf51609987ef15390fc751e2863202f" rel="nofollow" target="_blank" title=""&gt;Concern&lt;/a&gt;，检查并重写所有 datetime 类型字段。&lt;/p&gt;
&lt;h3 id="bit表达boolean"&gt;bit 表达 boolean&lt;/h3&gt;
&lt;p&gt;Rails 里的 boolean 类型在 MySQL 里用&lt;code&gt;tynyint(1)&lt;/code&gt;，接入的第二个数据库是用的&lt;code&gt;bit(1)&lt;/code&gt;。
我用了下面的方式做转换。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hidden&lt;/span&gt;
  &lt;span class="n"&gt;read_attribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:hidden&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\x01&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hidden&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;write_attribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:hidden&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;type_cast_from_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;presence&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\x01&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="其他"&gt;其他&lt;/h3&gt;
&lt;p&gt;时区的转换有些繁琐，希望能找到更简洁的办法。&lt;/p&gt;</description>
      <author>lingceng</author>
      <pubDate>Mon, 14 May 2018 17:54:20 +0800</pubDate>
      <link>https://ruby-china.org/topics/36770</link>
      <guid>https://ruby-china.org/topics/36770</guid>
    </item>
    <item>
      <title>关于 Rails 里的 render 方法</title>
      <description>&lt;p&gt;官方文档里有两个地方提到 render 的用法
在 Controller 里，&lt;a href="http://guides.rubyonrails.org/layouts_and_rendering.html#using-render" rel="nofollow" target="_blank"&gt;http://guides.rubyonrails.org/layouts_and_rendering.html#using-render&lt;/a&gt;，例如&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;:edit&lt;/span&gt;
&lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;plain: &lt;/span&gt;&lt;span class="s2"&gt;"OK"&lt;/span&gt;
&lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="vi"&gt;@product&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 View 里，&lt;a href="http://guides.rubyonrails.org/layouts_and_rendering.html#using-partials" rel="nofollow" target="_blank"&gt;http://guides.rubyonrails.org/layouts_and_rendering.html#using-partials&lt;/a&gt;，例如&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;render&lt;/span&gt; &lt;span class="s2"&gt;"shared/menu"&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;partial: &lt;/span&gt;&lt;span class="s2"&gt;"form"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;locals: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;zone: &lt;/span&gt;&lt;span class="vi"&gt;@zone&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;看到这里，render 的日常使用就差不多了。
但我们还想找找 render 更多细致的用法，于是去查 API，找到很多 render 的定义。
有点混乱，也没有一个说明了&lt;code&gt;render json: @product&lt;/code&gt;这样的用法。&lt;/p&gt;

&lt;p&gt;于是有了些疑问：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Controller 里的 render 在哪儿定义的？具体有哪些参数？&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;render json: @product&lt;/code&gt;这样的用法在哪儿实现的？&lt;/li&gt;
&lt;li&gt;View 的 render 在哪儿定义的？&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;带着这样疑问，通过代码调试，结合源码，找到了些答案。&lt;/p&gt;

&lt;p&gt;Controller 里的 render 定义应该在 AbstractController::Rendering#render。
这里"定义"有点不准确，因为往往有多次重载，姑且理解为"主要方法"的意思。&lt;/p&gt;

&lt;p&gt;这里的 render 其实是通过 render_to_body 这个方式实现的，render_to_body 是个 API 方法，主要实现在 ActionController::Renderers。
在 ActionController::Renderers 里有 add 的类方法，可以添加 Mine 类型的支持，文档里的例子是定制"render csv: &lt;a href="/csvable" class="user-mention" title="@csvable"&gt;&lt;i&gt;@&lt;/i&gt;csvable&lt;/a&gt;"。
ActionController::Renders 源码里就有 json, js, xml 的 Mine 类型的支持的实现。这里摘抄一段 js 的：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;add&lt;/span&gt; &lt;span class="ss"&gt;:js&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;content_type&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="no"&gt;Mime&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;JS&lt;/span&gt;
  &lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respond_to?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:to_js&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;js&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_js&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;js&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;这样就回答问题 2："render json: &lt;a href="/product" class="user-mention" title="@product"&gt;&lt;i&gt;@&lt;/i&gt;product&lt;/a&gt;" 是在 ActionController::Renderers 里实现的。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;但 ActionController::Renderers 里并没有&lt;code&gt;render "index"&lt;/code&gt;这样的用法实现。
跟踪发现，ActionCtroller::Base included ActionView::Layouts which included ActionView::Rendering。
ActionView::Rendering#render_to_body uses ActionView::Renderer#render.
ActionView::Renderer#render的文档里有说明，它会根据条件判断使用TemplateRender或者PartialRenderer渲染。
PartialRenderer 类有比较详细的文档，TemplateRender 的类没什么文档，它的说明主要在下面提到的 ActionView::Helpers::RenderingHelper#render。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;这里是很奇妙的一点，Controller 的模版渲染实现其实是通过 View 里面的 Renderer 实现的。&lt;/strong&gt;
不过想来也可以理解，View 层本来就负责对模版文件做渲染。
那么我们可以推测，在 controller 里我们其实也可以这样使用&lt;code&gt;render partial: 'shared/menu'&lt;/code&gt;。我测试了下，的确可以。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;至于问题3，相对简单些：在ActionView::Helpers::RenderingHelper#render定义的。&lt;/strong&gt;
这个 Helper 方法还顺便提供了两个很有意思的功能。&lt;/p&gt;

&lt;p&gt;一是 partial 可以当作 layout 来使用，&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;render&lt;/span&gt; &lt;span class="ss"&gt;layout: &lt;/span&gt;&lt;span class="s1"&gt;'shared/menu'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Content&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;二是在 View 层可以简化 partial 的用法&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;render&lt;/span&gt; &lt;span class="ss"&gt;partial: &lt;/span&gt;&lt;span class="s2"&gt;"form"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;locals: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;zone: &lt;/span&gt;&lt;span class="vi"&gt;@zone&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;%# 可简化为 %&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="s2"&gt;"form"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;zone: &lt;/span&gt;&lt;span class="vi"&gt;@zone&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;ul&gt;
&lt;li&gt;&lt;strong&gt;查View的render的用法，主要查ActionView::Helpers::RenderingHelper#render和PartialRenderer的文档。&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;查 Controller 的 render 的用法，比 View 里的多了 ActionController::Renderers 的功能。&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <author>lingceng</author>
      <pubDate>Fri, 23 Mar 2018 08:37:22 +0800</pubDate>
      <link>https://ruby-china.org/topics/35305</link>
      <guid>https://ruby-china.org/topics/35305</guid>
    </item>
    <item>
      <title>做为一个 Ruby 开发，如何持续学习</title>
      <description>&lt;p&gt;学会翻墙，用好 google，然后我们再说后面的事。
总结的不多，经验尚浅。&lt;/p&gt;
&lt;h3 id="Keep up with news"&gt;Keep up with news&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;rubyweekly&lt;/li&gt;
&lt;li&gt;rubyinside&lt;/li&gt;
&lt;li&gt;rubynews&lt;/li&gt;
&lt;li&gt;reddit/r/ruby&lt;/li&gt;
&lt;li&gt;reddit/r/rails&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="Know the persons"&gt;Know the persons&lt;/h3&gt;
&lt;p&gt;Persons in ruby community are kind.&lt;br&gt;
They do speeches, write blogs and publish books.&lt;br&gt;
Follow them on twitter to get news about them.
Add their blogs to RSS reader.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Aaron Patterson&lt;/li&gt;
&lt;li&gt;DHH&lt;/li&gt;
&lt;li&gt;Dave Tomas &lt;a href="https://en.wikipedia.org/wiki/Dave_Thomas_programmer)" rel="nofollow" target="_blank"&gt;https://en.wikipedia.org/wiki/Dave_Thomas_programmer)&lt;/a&gt;( &lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.arkency.com/" rel="nofollow" target="_blank"&gt;http://blog.arkency.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/orgs/rails/people" rel="nofollow" target="_blank"&gt;https://github.com/orgs/rails/people&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Github search with: language:Ruby followers:&amp;gt;300&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="Involve in"&gt;Involve in&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Read the source code of projects&lt;/li&gt;
&lt;li&gt;Report issues and fix bugs&lt;/li&gt;
&lt;li&gt;Maintain your open source project&lt;/li&gt;
&lt;li&gt;Share by blogs, speeches and books&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="http://lingceng.github.io/blog/2016/01/22/keep-learning-as-a-ruby-programmer/" rel="nofollow" target="_blank"&gt;http://lingceng.github.io/blog/2016/01/22/keep-learning-as-a-ruby-programmer/&lt;/a&gt;&lt;/p&gt;</description>
      <author>lingceng</author>
      <pubDate>Fri, 22 Jan 2016 09:42:14 +0800</pubDate>
      <link>https://ruby-china.org/topics/28815</link>
      <guid>https://ruby-china.org/topics/28815</guid>
    </item>
    <item>
      <title>用 ransack 做日期范围查询</title>
      <description>&lt;p&gt;我定制了两个 ransack predicates，让查询日期范围更好用。
其实就是让结束日期取那一天的 59:59 分&lt;/p&gt;

&lt;p&gt;代码如下：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Custom ransack predicate to simplify query for date range&lt;/span&gt;
&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;span class="c1"&gt;# See lib/ransack.rb in ransack gem&lt;/span&gt;
&lt;span class="c1"&gt;# See wiki https://github.com/activerecord-hackery/ransack/wiki/Custom-Predicates&lt;/span&gt;
&lt;span class="no"&gt;Ransack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;

  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_predicate&lt;/span&gt; &lt;span class="s1"&gt;'beginning_of_day_gteq'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;arel_predicate: &lt;/span&gt;&lt;span class="s1"&gt;'gteq'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;formatter: &lt;/span&gt;&lt;span class="nb"&gt;proc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beginning_of_day&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="ss"&gt;validator: &lt;/span&gt;&lt;span class="nb"&gt;proc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;present?&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="ss"&gt;type: :string&lt;/span&gt;

  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_predicate&lt;/span&gt; &lt;span class="s1"&gt;'end_of_day_lt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;arel_predicate: &lt;/span&gt;&lt;span class="s1"&gt;'lt'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;formatter: &lt;/span&gt;&lt;span class="nb"&gt;proc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end_of_day&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="ss"&gt;validator: &lt;/span&gt;&lt;span class="nb"&gt;proc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;present?&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="ss"&gt;type: :string&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;全文见：
&lt;a href="http://lingceng.github.io/blog/2015/12/28/query-date-range-with-ransack/?from=ruby-china.org" rel="nofollow" target="_blank"&gt;http://lingceng.github.io/blog/2015/12/28/query-date-range-with-ransack/?from=ruby-china.org&lt;/a&gt;&lt;/p&gt;</description>
      <author>lingceng</author>
      <pubDate>Mon, 28 Dec 2015 21:52:50 +0800</pubDate>
      <link>https://ruby-china.org/topics/28554</link>
      <guid>https://ruby-china.org/topics/28554</guid>
    </item>
    <item>
      <title>重用页面的表格做 �CSV 导出</title>
      <description>&lt;p&gt;rails 做 csv 导出挺容易的，只是大部分还是要组装二维数组。
我想直接抓取页面的表格做导出，这样页面显示时的一些转换也可以重用了。&lt;/p&gt;

&lt;p&gt;代码如下：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_csv_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;template&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;template&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;controller_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;action_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.html.slim"&lt;/span&gt;
  &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;render_to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="no"&gt;Nokogiri&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HTML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;at_css&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'table'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;css&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'tr'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;css&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'td,th'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ss"&gt;:text&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to_csv&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;

  &lt;span class="c1"&gt;# Convert from utf8 to gbk to make it compatible with Windows Office Excel&lt;/span&gt;
  &lt;span class="c1"&gt;# And Mac number can work with GBK too&lt;/span&gt;
  &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'GBK'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;undef: :replace&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;replace: &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;全文在这里 &lt;a href="http://lingceng.github.io/blog/2015/12/23/export-csv-or-excel-by-re-using-existing-html-view/" rel="nofollow" target="_blank"&gt;http://lingceng.github.io/blog/2015/12/23/export-csv-or-excel-by-re-using-existing-html-view/&lt;/a&gt;&lt;/p&gt;</description>
      <author>lingceng</author>
      <pubDate>Wed, 23 Dec 2015 20:46:46 +0800</pubDate>
      <link>https://ruby-china.org/topics/28503</link>
      <guid>https://ruby-china.org/topics/28503</guid>
    </item>
    <item>
      <title>在 Vim 或者命令行查单词 bing_dictionary</title>
      <description>&lt;p&gt;Bing Command Dictionry
这是一个 ruby 脚本，用来在命令行中直接查询单词含义，免去打开软件或浏览器的麻烦。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2014/b7c1f1d1ea2fb80bc3cb202eda684057.gif" title="" alt="demo"&gt;&lt;/p&gt;

&lt;p&gt;配合 vim 使用：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nnoremap &amp;lt;leader&amp;gt;d :!dict &amp;lt;cword&amp;gt;&amp;lt;CR&amp;gt;
vnoremap &amp;lt;leader&amp;gt;d y:!dict &amp;lt;c-r&amp;gt;"&amp;lt;CR&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href="https://github.com/lingceng/bing_dictionary" rel="nofollow" target="_blank"&gt;https://github.com/lingceng/bing_dictionary&lt;/a&gt;&lt;/p&gt;</description>
      <author>lingceng</author>
      <pubDate>Tue, 23 Dec 2014 14:26:18 +0800</pubDate>
      <link>https://ruby-china.org/topics/23358</link>
      <guid>https://ruby-china.org/topics/23358</guid>
    </item>
    <item>
      <title>ruby 写的代码克隆工具-CloneCode</title>
      <description>&lt;p&gt;&lt;a href="https://github.com/lingceng/clone-code" rel="nofollow" target="_blank" title=""&gt;CloneCode&lt;/a&gt; 可以快速地&lt;strong&gt;搬代码&lt;/strong&gt;，下面是个例子，工具可以进行批量操作，包括文件目录的复制。&lt;/p&gt;

&lt;p&gt;source HelloWorld.java&lt;/p&gt;

&lt;p&gt;public class HelloWorld {
      public static void main(String[] args) {
        System.out.println("Hello, I'm HelloWorld");
        String helloWorld = "HELLOWORLD";
        System.out.println(helloWorld);&lt;br&gt;
      }
    }&lt;/p&gt;

&lt;p&gt;Run commnad &lt;code&gt;ruby cc.rb -f HelloWorld -t WellDone -d 'doc/*.java'&lt;/code&gt;, replace &lt;strong&gt;HelloWorld&lt;/strong&gt; to &lt;strong&gt;WellDone&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;do with [doc/HelloWorld.java]
    replace [doc/HelloWorld.java] to file [doc/WellDone.java]&lt;/p&gt;

&lt;p&gt;result WellDone.java&lt;/p&gt;

&lt;p&gt;public class WellDone {
      public static void main(String[] args) {
        System.out.println("Hello, I'm WellDone");
        String wellDone = "WELLDONE";
        System.out.println(wellDone);&lt;br&gt;
      }
    }&lt;/p&gt;

&lt;p&gt;GitHub Repo:&lt;a href="https://github.com/lingceng/clone-code" rel="nofollow" target="_blank"&gt;https://github.com/lingceng/clone-code&lt;/a&gt;&lt;/p&gt;</description>
      <author>lingceng</author>
      <pubDate>Wed, 15 May 2013 10:13:40 +0800</pubDate>
      <link>https://ruby-china.org/topics/10990</link>
      <guid>https://ruby-china.org/topics/10990</guid>
    </item>
  </channel>
</rss>
