• 受教了,目前有类似的需求,决定试试 @fan124 的方案。

  • 我的一种实践:https://ruby-china.org/topics/35505

    react-rails gem + webpacker

  • @Rei 我之前看到你的评论了,没来得及回复,现在看好像你的内容已经改过了,我印象中你之前的评论中是说了关于前后端分离的情况,不过仔细看文章我话,其实我这个实践是没有做前后分离的,就用了 React 最最简单的一个功能,作为 view,用 react component 替代了原来的 html view 模板。router 也还是 rails 的 router,数据也都是在服务端产生,通过 props 传给 react component。这种用法几乎没有对原来的整体框架产生太大的变化。(即使不需要 SSR 也可以这么用)

    一开始这样做我也是觉得有些拧巴的,但后来我体会到了一些好处,我说说我的感受。

    1. 用 react component (我一直用 jsx 语法) 替代原来的 html view 模板来写 view,表达能力和灵活性都大大加强了 (有待举个例子进行一下对比,但我觉得大家对这一点应该是认可的,毕竟一个是编程语言,一个是标记语言),阅读调试我觉得都更加方便了。在原来的模板中,以 haml 为例,你 include 另一个模板,你都没法直接在编辑器里跳转过去。
    2. 我觉得用 react 另一个最大的好处在于,组件终于能完全复用了。我把一个组件封装好后,放到 npm 上,别人 install, import 一下基本就能马上用起来了。而如果你用一个基于 jQuery 实现的组件,首先要把 js 引进来,然后你需要在 html 中至少声明一个特定的标签,还有可能必须是指定的类名或 id,然后可能还需要调一下某个 js 方法来进行一下初始化。相比 react 组件的使用就麻烦了不少。

    这是 RateYo! 的使用示例:

    <-- HTML -->
    
    <head>
      <-- Basic styles of the plugin -->
      <link rel="stylesheet" href="jquery.rateyo.css"/>
    </head>
    
    <body>
      <div id="rateYo"></div>
    
      <script src="jquery.js"></script>
      <script src="jquery.rateyo.js"></script>
    </body>
    
    /* Javascript */
    
    //Make sure that the dom is ready
    $(function () {
    
      $("#rateYo").rateYo({
        rating: 3.6
      });
    
    });
    

    这是 React-Stars 的使用:

    import ReactStars from 'react-stars'
    import React from 'react'
    import { render } from 'react-dom'
    
    const ratingChanged = (newRating) => {
      console.log(newRating)
    }
    
    render(<ReactStars
      count={5}
      onChange={ratingChanged}
      size={24}
      color2={'#ffd700'} />,
    
      document.getElementById('where-to-render')
    );
    

    (代码行数上可能是没更少,但逻辑是集中在一起,没有割裂在不同的地方)

    相比传统 html view 模板,我想缺点可能就是性能问题,这个有待 profile 一下到底差多少。但如果对性能需求不是那么高的话,又不喜欢写 html view 模板,那么值得尝试一下这种方式。

    而且如果不需要考虑 SEO,那么就不需要为 React 做 SSR,那性能会和传统 html view 模板几乎没有差别。

    以上是我的一些拙见。

  • @Littlesqx 是的,但 js 代码是不是由 node 来执行的我还不确定。

    react-rails 文档上是这么说的:

    Server rendering is powered by ExecJS and subject to some requirements

    (https://github.com/reactjs/react-rails#server-side-rendering)

    而 ExecJS 是支持多种服务端的运行时的:

    ExecJS supports these runtimes:

    • therubyracer - Google V8 embedded within Ruby
    • therubyrhino - Mozilla Rhino embedded within JRuby
    • Duktape.rb - Duktape JavaScript interpreter
    • Node.js
    • Apple JavaScriptCore - Included with Mac OS X
    • Microsoft Windows Script Host (JScript)
    • Google V8
    • mini_racer - Google V8 embedded within Ruby

    (https://github.com/rails/execjs)

  • @qq2729877005 @uestc_bird

    rails 的默认行为是转义,如果你想输出富文本,又想保证安全,用 sanitize !

    你可以再看一下这个帖子:https://ruby-china.org/topics/16633 我在后面有追加提问。

  • 别用 raw 和 html_safe at 2018年02月07日

    @jasl ,有点明白了,是不是可以这样理解。

    转义并不能输出富文本,它输出的是原始文本。

    如果你想输出富文本,简单粗暴的方法是 <% raw danger_string %> 来实现的,但这样会有安全影患,所以要用 sanitize 来将富文本中危险的标签,比如 <script> 过滤掉。

    got it! 谢谢!

  • 别用 raw 和 html_safe at 2018年02月07日

    另外,好奇一下论坛帖子的排序顺序是怎么样的,为什么这个帖子有新的回复,我再回到社区首页,却找不到这个帖子呢?

  • 别用 raw 和 html_safe at 2018年02月07日

    @Rei @jasl 今天遇到了 HTML 转义和过滤的问题,看了好多资料,没有哪篇文章指出转义和过滤的区别,什么时候该用转义,什么时候该用过滤,还是两者一起用。

    我对下面三种表述做了一下对比 (ruby 2.3.3 & rails 5.0)

    <%= danger_string %>
    <%= sanitize danger_string %>
    <%= raw danger_string %>
    

    假设 danger_string 原始值是 <script>alert("xss");</script>,三者在 HTML 源码中分别是:

    &lt;script&gt;alert(&quot;xss&quot;);&lt;/script&gt;
    alert("xss");
    <script>alert("xss");</script>
    

    可见,第一种表述,即 rails 的默认行为,我觉得并不是过滤,而是转义。在前端界面中你可以看到完整的 <script>alert("xss");</script> 内容。

    第二种表述,sanitize 才是过滤,把 <script> 标签去掉了。在前端界面中你只能看到 alert("xss"); 的内容。

    第三种表述毫无疑问是会执行其中的 JavaScritp 代码的,并在前端页面中看不到内容。

    如果 danger_string 的原始值是 <em>haha</em>,三者在 HTML 源码中分别是:

    &lt;em&gt;haha&lt;/em&gt;
    <em>haha</em>
    <em>haha</em>
    

    第一种表达,在前端界面中,可以看到完整的 <em>haha</em> 内容。

    第二种和第三种,在前端界面中,看到的都是斜体的 haha。可见,sanitize 默认只对部分标签进行过滤。

    回到开头的疑问,想请教一下大家,转义和过滤,它们之间是一种什么关系?什么时候该用转义,什么时候该用过滤。

    另外,转义和过滤,可以发生在将数据存入到数据库时,也可以将原始内容原原本本存入数据库,只是在渲染时,将其转义和过滤,哪一种方式是更常采用的?

    谢谢!

  • 以下是我在看 《Agile Web Development Rails 5》时所做的笔记,不知道理解得是不是完全正确。

    Rails Sessions

    session 用来保持状态,不要和 cookie 混淆,它们只是有一点点交集而已。

    Session Storage

    Session 的存储方式 session_store,在 rails 中多达 6 种:

    • :cookie_store
    • :active_record_store
    • :drb_store
    • :mem_cache_store
    • :memory_store
    • :file_store

    这 6 种方式,除了第一种 :cookie_store 是存储在客户端,其余都是在服务端进行状态的持久化。而第一种也是最常用的方式,这就是为什么我们很容易把它和 cookie 混淆。cookie 是实现 session 的一种手段。

    我认为,人们常说的 cookie 有广义和狭义之分,广义的 cookie,就是被浏览器客户端持久化的这些对象,会在每次请求时被浏览器自动携带,它包括狭义的 cookie 和 session。狭义的 cookie 就是所有的 cookie 中除去 session 的那部分。

    如果采用 :cookie_store 方式的 session,数据失效很好处理,关闭浏览器,再打开浏览器,cookie 中的 session 部分就会被自动清空,所以这种方式 session 的有效周期维持在一个浏览器进程时长。这种方式将减轻服务端逻辑。

    如果采用服务端方式的 session,session 的生命周期是永久的,因此必须借助过期时间来清除过期的 session。另外,要注意,采用服务端方式的 session,并不是说就不需要往客户端存储任何数据了,还是需要的,只是只需要存储一个 session_id,然后通过 session_id 到服务端再去拿对应的其它数据。

  • 谢谢 @jasl ,我先看一下这个文档。