斷斷續續繼續了一些ruby編程的筆記,都是一些很繼續的東西,在簡書這裏彙總一下。
一:如何使用Pundit進行權限管理
1.1:pundit介紹
有名的權限管理gem:
1.pundit:流行的權限管理(推薦,pundit更加適合大型項目,更加複雜的權限系統)
2.authority: 已經不維護了
3.cancancan: 比較老牌的權限管理的gem
作用:針對不同的用戶執行不同的操作(不同的用戶有不同的角色管理)
注意:用戶級別的角色管理,pundit是不包含這個功能的,角色的管理需要我們自己來設計和實現
pundit這個gem是需要根據我們自己所需要的邏輯,比如哪樣的用戶能夠幹什麼事情,說白了就是哪些用戶
能夠執行這個action,哪些用戶可以執行特定的邏輯操作,總得來說,pundit主要是做後端的一個權限管理的一個gem.
1.2:Pundit安裝和配置
1.在Gemfile中引入:
gem 'pundit'
bundle install
3.在app/controller/application_controller.rb中引入pundit這個模塊
include Pundit
說明:引入pundit這個模塊之後,我們就可以在controller和view中使用對應的方法來判斷對應的權限了
4.運行pundit初始化命令
rails g pundit:install
說明:運行完這條命令之後會生成app/policies/application_policy.rb這個文件
5.在config/application.rb加入下面的語句,讓其能自動加載
config.autoload_paths += %W[#{config.root}/app/policies]
1.3:Pundit的使用
這裏首先要明確幾點:
- pundit策略的設置都是純根據ruby的類來實現的
- 一個方法,比如index?是否返回true和false,是我們能夠使用app/policies/application_policy.rb這個文件裏user、record兩個變量來判斷當前的action是否返回true和false
- policy設計的思路,每一個policy文件都是和模型對應的。比如傳過來的是一個post這個record,pundit就會查找app/policies/下是否有PostPolicy這個類,然後調用這個類的同名的這個方法,進而判斷權限,pundit和rails相似,有預先的約定和猜測。
舉個例子:
只有這個用戶發表的文章,他纔有刪改的權限
1)運行命令
rails g controller posts index show
在posts這個表創建個title這個列就行
2)在app/model/user.rb
下
class User < ApplicationRecord
has_many :user
end
app/model/post.rb
class Post < ApplicationRecord
belongs_to :user
end
3)在rails c中創建下測試數據
user = User.first
user.posts.create title: "Post 1"
user.posts.create title: "Post 2"
user2 = User.last
user.posts.create title: "Post 3"
user.posts.create title: "Post 4"
4)在app/controllers/posts_controller.rb中增加簡單的邏輯
class PostsController < ApplicationController
def index
@posts = Post.includes(:user)
end
def show
@post = Post.find params[:id]
end
def edit
@post = Post.find params[:id]
authorize @post #authorize是include Pundit提供的
end
end
5)在config/routes.rb增加對應的路由
resources :posts
6)view層
app/views/posts/index.html.erb
<h1>Posts</h1>
<ul class="list-group">
<% @posts.each do |post| %>
<li class="list-group-item">
<%= link_to post.title, post_path(post) %>,
ID: <%= post.id %>,
作者: <%= post.user.email %>
<% if policy(post).edit? %>
<%= link_to "編輯", edit_post_path(post), class: "btn btn-primary" %>
<% end %>
</li>
<% end %>
</ul>
app/views/posts/show.html.erb
<h1>Posts</h1>
<h2><%= @post.title %></h2>
<p>作者: <%= @post.user.email %></p>
app/views/posts/edit.html.erb
<h1>Posts</h1>
<h2>編輯:<%= @post.title %></h2>
7)app/policies/policy.rb
class PostPolicy < ApplicationPolicy
def edit?
user.has_role?('admin') || user == record.user
end
def can_edit?
true
end
end
說明:會識別PostPolicy這個類,ApplicationPolicy有個user屬性,指的是current_user,ApplicationPolicy在實例化的時候,會初始化這個屬性
二:log4R配置
1.在config目錄下,創建一個log4r的配置文件: config/log4r.yml,內容編輯如下
log4r_config:
# define all loggers ...
loggers:
- name : production
level : WARN
trace : 'false'
outputters :
- datefile
- name : development
level : DEBUG
trace : 'true'
outputters :
- datefile
# define all outputters (incl. formatters)
outputters:
- type: DateFileOutputter
name: datefile
dirname: "log"
filename: "my_app.log" # notice the file extension is needed!
formatter:
date_pattern: '%H:%M:%S'
pattern : '%d %l: %m '
type : PatternFormatter
2.修改config/application.rb文件如下
require 'rails/all'
# add these line for log4r
require 'log4r'
require 'log4r/yamlconfigurator'
require 'log4r/outputter/datefileoutputter'
include Log4r
Bundler.require(:default, Rails.env) if defined?(Bundler)
module Zurich
class Application < Rails::Application
#...
# assign log4r's logger as rails' logger.
log4r_config= YAML.load_file(File.join(File.dirname(__FILE__),"log4r.yml"))
YamlConfigurator.decode_yaml( log4r_config['log4r_config'] )
config.logger = Log4r::Logger[Rails.env]
end
end
3.修改gemfile文件,增加log4r這個gem
gem 'log4r', '1.1.9'
這時候重啓rails,就會發現log目錄,會根據日期創建相應的log目錄了。
三:後臺框架-activeadmin
activeadmin code:https://github.com/activeadmin/activeadmin
gemfile:
gem 'activeadmin'
# Plus integrations with:
gem 'devise'
gem 'cancan' # or cancancan
gem 'draper'
gem 'pundit'
bundle install
3.1 set-up activeadmin
如果你不想使用devise
rails g active_admin:install --skip-users
如果想用已經存在的User
rails g active_admin:install User
other
rails g active_admin:install
會生成這些文件
app/admin/dashboard.rb
app/assets/javascripts/active_admin.js
app/assets/stylesheets/active_admin.scss
config/initializers/active_admin.rb
然後依次執行一下命令
rake db:migrate
rake db:seed
rails server
這些在官網安裝指南介紹的都很詳細,這裏列出我在實際項目中會用到的一些功能。
這裏也可以嘗試一下實際效果
3.2 自定義action
ActiveAdmin.register User do
index do
actions do |u|
link_to('獲取用戶下級所有姓名', "/admin/users/#{u.id}/get_names", method: 'get')
end
end
end
member_action :get_names, :method => :get do
#處理業務邏輯,這裏get請求,接收params[:id]參數
render json: your_json_info
end
3.3 scope、filter、selectable_column、
1.scope:列表上面進行對列表中數據進行篩選,在model有需要有專門的方法存在。
2.filter:filter默認會過濾所有model的數據,這裏如果指定,將會覆蓋原本默認存在的。
3.4 index
1.selectable_column:在列表左方增加可以選擇的按鈕,這裏一般是爲了可以進行批量刪除/處理操作。
2.id_column:顯示字段的id字段。
3.如果不定義index是默認顯示全部。跟filter一個道理,這裏定義column
可以根據實際需要顯示需要展示的列。
3.5 form
1.用input來定義需要添加/修改的列
如果需要將某幾個字段放在一起,然後用指定的名字定義下面的字段,可以這樣寫:
form do |_|
inputs '這裏展示區域_a' do
column: a_1
column: a_2
end
end
另外input中針對於特殊字段,可以顯示出特定的格式:
1.1 日期:
input :push_start_time, as: :datepicker, label: '開始時間' #這裏顯示的是yyyy-mm-dd
input :push_start_time, as: :date_picker, label: '開始時間' #這裏顯示的是yyyy-mm-dd mm:dd::ss
1.2 下拉:
input :order_info, as: :select, collection: [['有訂單', true], ['無訂單', false]], label: '適用人羣', selected: '有訂單' #下拉按鈕,這裏可以設置選中哪一個
1.3 上傳:
input cover as: file, label: "封面", hint: "233x292"
1.4 單選:
input :plans, as: :check_boxes,
label: '人員限制',
collection: [:user_a, :user_b],
selected: :user_a #注意,這是是symbol
這裏有一個值得注意的點,我發現每次保存的時候,都無法將plans保存到數據庫中,我在permit_params也寫入了plans,對了在admin/你的model.rb中需要寫入permit_params,這裏是允許哪些字段,這就是rails的健壯參數了,這裏不多做概述,迴歸整體,這裏針對於plans不能寫
permit_params :plans
因爲plans是check_boxes,這裏需要指定格式
permit_params plans: []
這樣就好了
3.6 other
1.還有一種情況,你可能在設計表的時候,可能採用一個列中存在多個字段的情況,這就需要在model進行序列化的操作,那在activeadmin中如果展示出來呢
看下面的兩個文檔,或許能解決你的問題:
JSON Serialized Columns with Rails
Dealing with JSON data in Active Admin
2.針對於notice flash消息不能正常顯示的問題
Add flash messages for actions
四:rails中的reject和merge方法
在進行rails開發的時候,針對於hash最常用的方法是reject和hash的方法
4.1 reject方法
1)reject方法和描述
hash.reject { |key, value| block }
類似 delete_if, 但作用在一個拷貝的哈希上。相等於 hsh.dup.delete_if。
2)reject!方法和描述
hash.reject! { |key, value| block }
相等於 delete_if, 但是如果沒有修改,返回 nil。
2.3.3 :001 > h = {:a => 1, :b => 2}
=> {:a=>1, :b=>2}
2.3.3 :002 > h.delete(:a)
=> 1
2.3.3 :003 > h
=> {:b=>2}
2.3.3 :004 > h = {:a => 1, :b => 2}
=> {:a=>1, :b=>2}
2.3.3 :005 > h.delete_if {|k,v| v != 3}
=> {}
2.3.3 :006 > h
=> {}
2.3.3 :007 > h = {:a => 1, :b => 2}
=> {:a=>1, :b=>2}
2.3.3 :008 > h.reject{|k, v| v!=2}
=> {:b=>2}
2.3.3 :009 > h
=> {:a=>1, :b=>2}
2.3.3 :010 > h = {:a => 1, :b => 2}
=> {:a=>1, :b=>2}
2.3.3 :011 > h.reject!{|k, v| v!=2}
=> {:b=>2}
2.3.3 :012 > h
=> {:b=>2}
2.3.3 :015 > h = {:a => 1, :b => 2}
=> {:a=>1, :b=>2}
2.3.3 :016 > h.reject{|k, v| v!=2}
=> {:b=>2}
2.3.3 :017 > h
=> {:a=>1, :b=>2}
2.3.3 :018 > h.reject!{|k, v| v!=2}
=> {:b=>2}
2.3.3 :019 > h
=> {:b=>2}
2.3.3 :020 > h.reject!{|k, v| v!=2}
=> nil
4.2 merge方法
1)merge方法和描述
hash.merge(other_hash) [or]
hash.merge(other_hash) { |key, oldval, newval| block }
2)merge!方法和描述
hash.merge!(other_hash) [or]
hash.merge!(other_hash) { |key, oldval, newval| block }
與 merge 相同,但實際上 hash 發生了變化。
other
更基礎的東西,請看這篇ruby基礎彙總