提供分頁功能
will_paginate 如何使用
controller : posts/index
@posts = Post.includes(:user)
改成
@posts = Post.includes(:user).paginate(page: params[:page], per_page: 5)
view : posts/index
<% @posts.each do |post| %>
<%= post.title %>
<% end %>
<%= will_paginate @posts %>
will_paginate not working
如果傳入的是 ActiveRecord_Associations_CollectionProxy 而不是 ActiveRecord_Relation 可能會造成此狀況,在 controller 要額外引入
require 'will_paginate/array'
bootstrap 樣式
view :
<%= will_paginate @posts, :renderer => PaginationLinkRenderer %>
config/initializers/pagination_link_renderer.rb :
require 'will_paginate/view_helpers/link_renderer'
require 'will_paginate/view_helpers/action_view'
class PaginationLinkRenderer < ::WillPaginate::ActionView::LinkRenderer
protected
def page_number(page)
unless page == current_page
tag(:li, link(page, page, :rel => rel_value(page)))
else
tag(:li, link(page, '#', :rel => rel_value(page)), :class => "active disabled")
end
end
def gap
tag(:li, link('...' , '#') , :class => "disabled")
end
def previous_or_next_page(page, text, classname)
tag(:li, link(text , page || '#'), :class => page ? classname : classname + ' disabled')
end
def html_container(html)
tag(:div , tag(:ul, html , container_attributes) , :class => 'pagination_label col-xs-12 center')
end
end
小技巧 - 簡化 view 的分頁
在 controller 多指定變數給 @paginate
@users = @paginate = User.all.paginate(:page => params[:page] , :per_page => 15)
不必擔心 @users
跟 @paginate
佔兩份記憶體, 它們都指向同一個 object_id
view/layout
<%= raw(will_paginate(@paginate ,:renderer => PaginationLinkRenderer)) if @paginate %>
在 layout 放這段, 讓 renderer 覆寫掉原生的 gem (寫在 initializers 裡, 可參考本篇 bootstrap 那邊寫法), 就不用每一個 view 都要寫 will_paginate
之後只要在需要分頁的 view 直接 <%= @paginate %>
就好
其他
取得總數
@products.total_entries
FB Oauth
如果使用 Devise,請不要用下列的方法,請到這篇搜尋 oauth-facebook
申請 FB APP
-
Developers
-
Add a New App 選擇 Website (網站)
-
建立 App -> 輸入一個 Name -> 按步驟 -> Create a New App ID
-
建立成功, 下面有個欄位輸入 Domain : http://test.example.com:3000/
如果沒有 domain 可以暫時用 ngrok,但注意!FB 登入時要用 http://e2191881.ngrok.io/
而不是 http://127.0.0.1:3000/
-
右上角大頭像的 My Apps 選剛剛建立的 App
-
將 App ID 及 App Secret Copy 貼到安裝完 omniauth 的設定檔 config/initializers/omniauth.rb
如果日後要換 domain 一樣在 App Dashboard 頁面, 在 App ID 下面那塊, 選擇 Choose a Platform -> WWW -> 就可以改 domain 了
Install
Gemfile
gem 'omniauth', '~> 1.3.1'
gem 'omniauth-facebook', '~> 3.0.0'
安裝完重啟動 rails
新增 User model
rails g model User provider uid name oauth_token oauth_expires_at:datetime
或直接建立
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :provider
t.string :uid
t.string :name
t.string :oauth_token
t.datetime :oauth_expires_at
t.timestamps null: false
end
end
end
app/models/user.rb
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.provider = auth.provider
user.uid = auth.uid
user.name = auth.info.name
user.oauth_token = auth.credentials.token
user.oauth_expires_at = Time.at(auth.credentials.expires_at)
user.save!
end
end
寫入後資料如下
:id => 1,
:provider => "facebook",
:uid => "860********7924",
:name => "Test Account",
:oauth_token => "CAAF5japY********************n7hjii",
:oauth_expires_at => Sat, 10 Oct 2015 14:26:09 UTC +00:00,
新增 Sessions Controller
app/controllers/application_controller.rb
private
def current_user
@current_user ||= User.find(session[:user_id]) if session[:user_id]
end
helper_method :current_user
app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
def create
user = User.from_omniauth(env["omniauth.auth"])
session[:user_id] = user.id
redirect_to root_url
end
def destroy
session[:user_id] = nil
redirect_to root_url
end
end
新增 routes
config/routes
match 'auth/:provider/callback', to: 'sessions#create', via: [:get, :post]
match 'auth/failure', to: redirect('/'), via: [:get, :post]
match 'signout', to: 'sessions#destroy', as: 'signout', via: [:get, :post]
手動建立 Omniauth initializer
config/initializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
provider :facebook, '41512******2503', '1791f7944e*********7ebaa65989414'
end
登入 / 登出
app/views/welcome/index.html.erb
<div id="user-widget">
<% if current_user %>
<%= link_to "Sign out", signout_path, id: "sign_out" %>
<% else %>
<%= link_to "Sign in with Facebook", "/auth/facebook", id: "sign_in" %>
<% end %>
</div>
(選項, 可不加) JS :
$(document).ready(function () {
$('body').prepend('<div id="fb-root"></div>')
$.ajax
url: "#{window.location.protocol}//connect.facebook.net/en_US/all.js"
dataType: 'script'
cache: true
window.fbAsyncInit = ->
FB.init(appId: 'YOUR-APP-ID', cookie: true)
$('#sign_in').click (e) ->
e.preventDefault()
FB.login (response) ->
window.location = '/auth/facebook/callback' if response.authResponse
$('#sign_out').click (e) ->
FB.getLoginStatus (response) ->
FB.logout() if response.authResponse
true
});
ref : https://coderwall.com/p/bsfitw/ruby-on-rails-4-authentication-with-facebook-and-omniauth
Gemfile
gem 'bootstrap-sass', '~> 3.3.5'
gem 'sass-rails', '>= 3.2'
application.scss (注意副檔名是 .scss
)
// "bootstrap-sprockets" must be imported before "bootstrap" and "bootstrap/variables"
@import "bootstrap-sprockets";
@import "bootstrap";
application.js
//= require jquery
//= require bootstrap-sprockets
當用 rails console 撈資料時, 欄位多會造成很難閱讀, 可以藉由 awesome_print 使輸出時好看一點
Gemfile
gem 'awesome_print'
Usage
$ rails console
> ap User.find(1)
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 1]]
#<User:0x007f9755c5be78> {
:id => 1,
:email => "root@gmail.com",
:encrypted_password => "$2a$10$/O5sGBe8KonKehd1GIFdaeh.RyDdApKmr60gr5t93Zql1S..WqiuS",
:reset_password_token => nil,
:reset_password_sent_at => nil,
:remember_created_at => nil,
:sign_in_count => 2,
:current_sign_in_at => Sat, 04 Jul 2015 09:17:54 UTC +00:00,
:last_sign_in_at => Sat, 04 Jul 2015 09:14:21 UTC +00:00,
:current_sign_in_ip => "127.0.0.1",
:last_sign_in_ip => "127.0.0.1",
:created_at => Sat, 04 Jul 2015 09:12:24 UTC +00:00,
:updated_at => Sat, 04 Jul 2015 09:17:54 UTC +00:00,
:confirmation_token => nil,
:confirmed_at => Sat, 04 Jul 2015 09:12:23 UTC +00:00,
:confirmation_sent_at => nil
}
=> nil
Cron jobs
有時候主機需要一個背景需要可以一直跑的程式, 例如幫你檢查 DB 某個欄位再做對應的事
Install
gem 'whenever', :require => false
bundle install
wheneverize .
會產生 config/schedule.rb
, 在這裡定義你的 cron job
注意! 無法直接在 schedule 裡寫 Rails 語法, 維持這裡的乾淨, 定義 cron job 要做的事情就好, 把任務定義在 task
Example
每一分鐘寫入一次檔案或 task
every 1.minute do
command "/bin/echo '1' >> /tmp/test"
rake "schedule:find"
end
every 30 minutes between 6 to 9.
every '*/30 6-9 * * *' do
runner "Model.method"
end
使用步驟
預設的定義檔路徑是 config/schedule.rb
, 所以要到 rails app 下執行
-
查看轉換為 cron syntax 的語法, 但還不會寫入
whenever
whenever –set environment=development # 執行 rake 必須加上
whenever 執行 rake 指令預設是 production,
-
寫入 cron
whenever -w
或 update
whenever -i
如果一次 update development 及 production 環境的 schedule, 但只會有一種被寫進 cronjob
註) 啟動後 cron job 就會開始跑了, 因為它是使用系統的 cron job, 所以即使 rails 沒啟動它仍然會在背景跑
如果在啟動後輸入 crontab -e
就會看到剛剛寫入的以下內容
# Begin Whenever generated tasks for: /Users/test/Desktop/projects/rails/translate/config/schedule.rb
* * * * * /bin/bash -l -c '/bin/echo '\''1'\'' >> /tmp/test'
# End Whenever generated tasks for: /Users/test/Desktop/projects/rails/translate/config/schedule.rb
Rails 的 production 與 dev 的 cronjob 可同時存在
清除 cron job
whenever -c
在同一個 Rails app 不管執行的是 production, development 都會被清掉
example
lib/tasks/schedule.rake
namespace :schedule do
desc "TODO.."
task :find do
Rails.logger.info(1)
end
end
缺點
它是在執行的時候從頭啟動 rails 再執行你的 function,會有這麼一點效能浪費,我覺得是個小問題
是否該使用 sitemap 可以根據 google 的手冊來決定
-
根據這個套件的 README 就可以順利安裝, 記得將 sitemap.rb
放在根目錄, 因為產生的 sitemap.xml.gz
會被放在 public/
下
-
記得在 robots.txt
加上
Sitemap: https://www.example.com/sitemap.xml.gz
-
到 google 的 search console 加入你的網站 (會要求你用一些方法確認是你的網站, 加上 <meta>
標簽的方法較簡單), 加入成功後左邊 menu 選擇 Sitemap 並且提交