rails3中使用facebox

26 Jul 2011 \ fleuria ->

(有两个月没有更新了?这又是例行工事的凑数文。)

真正接触rails的时间并不长,先前几个心不在焉的小东西烂尾之后,就一直觉得跟不上rails中各种约定的思路,也一直没有学好。直到最近在家没事搞个小项目,权当实习之前的预习,才发现上手还是很快的。所谓“约定”,就是“同一种问题使用同一种解决方法”,而且往往也正是“最好的方法”。用过一遍之后如果能留下个好印象,就该差不多了。

ajax的相关内容在Rails Guide中似乎并未提及,因此在这里记一下。假定已经实现了一个非ajax表单,就像豆瓣收藏一本书的表单一样:

需要做的是,将这个表单放到facebox里:

jquery-ujs

先将rails默认的js框架改为jquery。

在Gemfile中加入:

gem 'jquery-rails', '>= 1.0.12'

然后

bundle install
rails generate jquery:install

换用jquery之后,把各种js都生成到html里的link_to_remote就不能使用了。可行的做法是在link_to中加上一个:remote => true,生成的代码会像是这样:

<a href="/favorites/4e2e7a331c78b4288b000005/edit" data-remote="true"> 想读 </a>

仅仅多了一个data-remote="true",专门给jquery看的一个属性。如果用户点击这个链接,触发一个js事件弹出facebox;如果用户要从新标签中打开这个链接,就可以见到原先非ajax的那个表单。

(ps: data-remote这种自定义属性似乎是html5加入标准的?如果是<a href="" remote=""></a>这样写,在浏览器生成DOM时会被省略掉,jquery也就读不出来,解决方案就是加一个data-前缀。)

约定

只要是:remote => true的链接,在用户点击时就会通过ajax获取一段动态生成的js代码并执行,不同的:action对应的js代码不同。这些js代码的模板都放在views里,比如"/favorites/4e2e7a331c78b4288b000005/edit"这个RESTful的链接,对应的:controller是Favorites,:action是edit,这段js代码也就对应着edit.erb.js。

原先的Controller:

class Favorites
...
  def edit
    @favorite = Favorite.find params[:id]
    @favorite.state = params[:state] if params[:state]
  end
 ...
 end
修改后:
class Favorites
...
  def edit
    @favorite = Favorite.find params[:id]
    @favorite.state = params[:state] if params[:state]
    respond_to do |format|
      format.html 
      format.js { render :ajax_edit, :layout => false }
    end
  end
..
end
其中respond_to是根据mime类型分派render的内容。获取的是js代码,mime类型肯定就是text/javascript了。在这段js里面打开facebox即可。 表单的内容呢?嵌到js代码里面。重构下代码,把edit.haml中的内容移动到_form_edit.haml中,在edit.haml里只留一行=render :template => 'favorites/_form_edit.haml' ajax_edit.erb.js
var form_html = '<%= escape_javascript(render :template => 'favorites/_form_edit') %>';
$.facebox(form_html);

javascript并无heredoc那种多行字符串的语法,escape_javascript可以将多行的字符串转义成单行。

这样就好了。提交表单时还会刷新下页面,不过若要修改成不需刷新的ajax表单,也就是按这路数再走一遍的功夫。

hosted on github, and powered by jekyll. (rss)