ADZ 學習筆記

Ruby/Rails, Startup, Life

Posts match “ rails ” tag:

rails 筆記 - rails 分頁 will_paginate + bootstrap + i18n

| Comments

in gem file

gem 'bootstrap-will_paginate' 
gem 'will-paginate-i18n', :git => 'https://github.com/afunction/will-paginate-i18n'

in controller

def index   
    @courses = Course.all.page(params[:page]) 
    # or 
    @courses = Course.all.page({page: @page, per_page: 20}) 
end

in view

<!-- Bootstrap style -->
<%= will_paginate(@courses) %> 

<!-- will_paginate default style -->
<%= will_paginate(@courses, :renderer => WillPaginate::ActionView::LinkRenderer) %>

https://github.com/yrgoldteeth/bootstrap-will_paginate
https://github.com/afunction/will-paginate-i18n

ruby on rails (第三週)

| Comments

曾經看到一些評論說 zend framework 只是一包 library 並不算是個 framework,當時真的滿不爽的,直到最近用 rails 完成了一個 project deploy 上 production 後才發現,這真的不是說假的,我怎麼會這麼晚才接觸 rails!!!

目前接觸到的 Gems

  1. devise - 快速 generate 出一個充滿修改彈性的會員系統
  2. sass-rails - 不用再打 scss --watch xxx.scss:public/css/xxx.css
  3. rails-i18n - 世界各國語言包 (datetime format, relative time , error messages, currency format)
  4. jbuilder - json generator
  5. bootstrap-sass-rails - bootstrap-sass for rails,剛更新 3.x .. rc 結束沒幾天,速度也太快了!
  6. will_paginate - 專門做分頁的 gem

目前接觸到的 Keywords

  1. asset pipeline - deploy 不用在 "人工" minify static file,順便解決更新檔案 user browser cache 問題
  2. Active Record Migration - db schema 隨著 project 一起納入版本控制
  3. rails router + view helper - url & controller/action map
  4. Active Record - ZF 的 DbTable 輸了
  5. Strong parameter - 把資料欄位/資料 validation 寫在 model,controller(resources) 限制可接受的 parameter 這種設計真的超 smart,既安全又彈性,重點是比 php 少寫太多 code 了啦!!!
  6. scaffold - RESTful CRUD generator (views, controller, model, test)

rails 筆記 - 封閉會員網站 scaffold controller & devise

| Comments

最近案子的需求是一個封閉系統,只能由有 admin 權限的 user 才能創造 user,首先設定 router

routes.rb
devise_for :users, :skip => [:sessions, :password, :registrations] do
  get "/login" => "users/sessions#new", :as => :new_user_session
  get "/logout" => "devise/sessions#destroy", :as => :destory_user_session
  post "/do-login" => "users/sessions#create", :as => :user_session
end

突然想到,既然關閉 registrations controller,那我要怎麼創造第一個 user ... !? user table 內的密碼不是加密過的嗎? 那 devise 的加密 funnction 在哪? google 了一下看到有人用 rails c 的方式

rails c
new_user = User.new
new_user.email = 'xxx@domain.com'
new_user.password = 'password'
new_user.password_confirmation = 'password'
new_new.save

比想像中更簡單直覺,果然學新東西,必須先把思維拋掉!!

但奇怪的一點是 User 沒有 password & password_confirmation 欄位,User Model 也只 extend ActiveRecord::Base,但裝好 devise 後,突然跑出這兩個欄位,不知道是透過什麼方式 inject 這些 property 到 user model 裡面去的,還實做好 password_confirmation 的檢查,只能說這真是太神奇了!!!

成功創造第一個 user 後,順便寫在 seeds.rb 裡

seeds.rb
if User.where({username: 'admin'}).count == 0
  User.create!(:username => 'admin', :password => 'password', :'password_confirmation' => 'password')
end

接下來是新增會員的功能,原本想說直接讓管理者透過 devise registrations controller 來新增會員,但看到一篇 github上的討論 以後,還是用決定用 scaffold,查一下有沒有可以 skip-model 之類的 option,結果直接看到 rails g 裡有一個項目 scaffold_controller

Description:
    Stubs out a scaffolded controller, its seven RESTful actions and related
    views. Pass the model name, either CamelCased or under_scored. The
    controller name is retrieved as a pluralized version of the model name.

就是這個,直接 ..

rails g scaffold_controller admin/user

建好後

routers.rb
namespace :admin do
    resources :users
end
admin/users_controller.rb
# GET /admin/users/1

def index
    @admin_users = Admin::User.all
end

# GET /admin/users/new

def new
    @admin_user = Admin::User.new
end
# ... (略)

發現在 admin/users_controller.rb 都是使用 Admin::User,但實際上要操作的 model 並不是在 admin/ 內,於是就把全部 Admin:: 拿掉,然後開啓頁面後 error ... user_path undefinded

打開 view

admin/users/index.html.erb
<tr>
    <td><%= link_to 'Show', admin_user %></td>
    <td><%= link_to 'Edit', edit_admin_user_path(admin_user) %></td>
    <td><%= link_to 'Destroy', admin_user, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>

本來有點不解為什麼 Show & Destroy 的 link_to 第二個參數可以直接把 admin_user 帶入,之後想想,也許這種寫法會直接使用當前 activerecordmodel 名稱產生對應的 view helper,如果是這樣,那這種設計真的很 smart,現在稍微體會 rails Convention over configuration 所帶來的效率,也開始覺得 rails 應該不是 for 剛接觸程式語言的人 ...

修改後的 view

admin/users/index.html.erb
<!-- .. (略) -->
<%= link_to 'Show', admin_user_path(admin_user.id) %>
<%= link_to 'Destroy', admin_user_path(admin_user.id), method: :delete, data: { confirm: 'Are you sure?' } %>
<!-- .. (略) -->

成功 :)

之後在編輯和新增的畫面出現錯誤,看來 form_for 也有類似問題

admin/users/_form.html.erb
<%= form_for(@admin_user) do |f| %>
<!-- ... (略) -->
<% end %>

這次解法就不是改 path helper

admin/users/_form.html.erb
<%= form_for(['amdin', @admin_user]) do |f| %>
<!-- ... (略) -->
<% end %>

其實我也看不太懂這是什麼用法,也許是指定 namspace admin 底下的 resources path 吧!! 總而言之,CRUD 都正常了,剩下最後一步 ... Admin::UsersController 加上 is_admin 檢查

admin/users_controller.rb
class Admin::UsersController < ApplicationController
    before_filter :admin_checker
  protected
  def admin_checker
    if current_user.is_admin? == false
        flash[:notice] = 'access denied'
      redirect_to root_path
    end
  end
    #... (略)

end

收工 :)

rails 筆記 - jquery-ujs has already been loaded! 錯誤

| Comments

今天遇到一個很奇怪的問題,頁面上有幾個 link,在連續點的時候發現一直出現下面錯誤

jquery-ujs has already been loaded!

看了 jquery-ujs 的 code

jquery-ujs.js
if ($.rails !== undefined) {
    $.error('jquery-ujs has already been loaded!');
}

想說奇怪,只是一般點了一般的 link,重新載入頁面怎麼會有 $.rails 存在,再檢查 http request

不是正常的 200 ok,看來因為某種原因頁面沒有重新載入,為了確認寫了以下 js

application.js
if (typeof(X) === 'undefined') {
    X = 1;
} else {
    X = X + 1;
}
console.log(X);

結果還真的點了一般 link,X 一直增加 ... 卡了 30 分鐘後發現 application.js 裡面有一行 turbolinks,google 了一下,原來 turbolinks 是透過非同步方式不讓頁面整個 reload 來增加效能。

application.html.erb
<%= javascript_include_tag "application", "data-turbolinks-track" => false %>

最後把 turbolinks 拔掉就好了,但操作上也感覺慢了一點 ..

Rails 筆記 - Devise Upgrade 3.1.0

| Comments

今天 bundle update 後 rails c 出現錯誤

/Users/eddie/.rvm/gems/ruby-2.0.0-p247/gems/devise-3.1.0/lib/devise/rails/routes.rb:440:in `raise_no_secret_key': Devise.secret_key was not set. Please add the following to your Devise initializer: (RuntimeError)

config.secret_key = '6906a7107d8e7bbf5f973853d5453517eb30908575f3617f7a1fbe207910edafc5cce6bd9e77a8336bca7ee937edb7621e732696c1913b7b10ba429e74ce1ce1'

把新增加的 config.secret_key 加在 initializers/devise.rb 後,發現重設密碼和驗證信的 link 都失效了,傳來的 confirm_token 跟 database 裡面的一樣,卻無法正確驗證成功,google 了一下原來是 devise 增加 secret_key 來 encrypt reset password & confirm token,必須跟著修改 devise mailer view。

# devise/mailer/confirmation_instructions.html.erb

confirmation_url(@resource, :confirmation_token => @resource.confirmation_token) #原來的 link 

confirmation_url(@resource, :confirmation_token => @token) #修改後的 link


# devise/mailer/reset_password_instructions.html.erb


edit_password_url(@resource, :reset_password_token => @resource.reset_password_token) #原來的 link

edit_password_url(@resource, :reset_password_token => @token) #修改後的 link

Devise github commits:

https://github.com/plataformatec/devise/blob/2a8d0f9beeb31cd2287094c5dcf843d0bd069eb8/app/views/devise/mailer/reset_password_instructions.html.erb#L5

https://github.com/plataformatec/devise/commit/d56641f514f54da04f778b2a9b816561df7910c2