認可の習作: Action Policy: 準備
外観
目的
認可の習作にAction Policyを用いたいと思います。
記事が長くなったので二回に分けました。
1. 準備(アプリを作成します)
2. 入門(Action Policyを導入します)
環境
macOS 10.15.5
Ruby 2.7.1
Rails 6.0.3.1
Yarn 1.22.4
Node 13.12.0
action_policy 0.4.3
参照
リポジトリ
https://github.com/usutani/try_action_policy
準備
Rails new
テストは選択肢として残しておきます。
rails new -M --skip-active-storage try_action_policy
cd try_action_policy
Gemfile
jbuilderは使いません。
# gem 'jbuilder', '~> 2.7'
bundle install
config/routes.rb
ルーティングの骨格を決めます。
Rails.application.routes.draw do
resources :users, only: %i[index show]
resources :posts do
resources :comments, only: %i[create destroy]
end
root to: 'users#index'
end
ロールの追加
ロールを持つユーザを作成します。
bin/rails g scaffold User name role:integer
db/migrate/*_create_users.rb
t.string :name, null: false
t.integer :role, null: false, default: 0
bin/rails db:migrate
app/models/user.rb
class User < ApplicationRecord
validates :name, presence: true
enum role: { general: 0, admin: 1 }
end
db/seeds.rb
admin = User.create! name: 'Administrator', role: 1
foo = User.create! name: 'Foo'
bar = User.create! name: 'Bar'
bin/rails db:seed:replant
bin/rails c
User.first.admin?
User.second.admin?
擬似認証
ユーザ一覧でクリックしたユーザを認証します。
app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
before_action :ensure_authenticated_user
private
def authenticate_user(user_id)
if authenticated_user = User.find_by(id: user_id)
cookies.encrypted[:user_id] ||= user_id
@current_user = authenticated_user
else
@current_user = nil
cookies.delete(:user_id)
nil
end
end
def ensure_authenticated_user
authenticate_user(cookies.encrypted[:user_id]) || redirect_to(root_url)
end
end
Typoしていないかを確認しておきます。
bin/rails s
app/controllers/users_controller.rb
skip_before_action :ensure_authenticated_user
# ...
def show
authenticate_user(params[:id])
redirect_to posts_url
end
authenticate_userの動作を確認しておきます。posts_urlは未実装なのでエラーになります。
bin/rails s
※この時のようにauthenticate_userをAuthentication concernとしても良いと思います。
ユーザ名の表示
app/views/layouts/application.html.erb
<body>
<div>
<% if @current_user %>
Signed in as <strong><%= @current_user.name %></strong>!
<% end %>
</div>
<%= yield %>
</body>
bin/rails s
PostのCURD
bin/rails g scaffold Post title content:text user:belongs_to
bin/rails db:migrate
db/seeds.rb
admin = User.create! name: 'Administrator', role: 1
foo = User.create! name: 'Foo'
bar = User.create! name: 'Bar'
Post.create! title: 'Admin post', content: "Administrator's post.", user: admin
Post.create! title: 'Foo post', content: "foo's post.", user: foo
Post.create! title: 'Bar post', content: "bar post.", user: bar
bin/rails db:seed:replant
bin/rails g model Comment content:text user:belongs_to post:belongs_to
bin/rails db:migrate
db/seeds.rb
admin = User.create! name: 'Administrator', role: 1
foo = User.create! name: 'Foo'
bar = User.create! name: 'Bar'
p1 = Post.create! title: 'Admin post', content: "Administrator's post.", user: admin
p2 = Post.create! title: 'Foo post', content: "foo's post.", user: foo
p3 = Post.create! title: 'Bar post', content: "bar's post.", user: bar
[p1, p2, p3].each do |post|
Comment.create! content: "Administrator's comment.", user: admin, post: post
Comment.create! content: "Foo's comment.", user: foo, post: post
Comment.create! content: "Bar's comment.", user: bar, post: post
end
bin/rails db:seed:replant
app/models/post.rb
class Post < ApplicationRecord
belongs_to :user
has_many :comments, dependent: :destroy
end
Commentの表示と作成
mkdir app/views/comments
touch app/views/comments/_comments.html.erb
touch app/views/comments/_comment.html.erb
touch app/views/comments/_new.html.erb
<section id="comments">
<%= render post.comments %>
</section>
<%= render 'comments/new', post: post %>
<article>
<h3>Comment by <%= comment.user.name %></h3>
<p><%= comment.content %></p>
</article>
<%= form_with model: [post, Comment.new], id: "new_comment" do |form| %>
<%= form.text_area :content %><br>
<%= form.submit 'Post comment' %>
<% end %>
app/views/posts/show.html.erb
...
<br>
<%= render 'comments/comments', post: @post %>
bin/rails s
open http://localhost:3000/posts
Commentの作成
bin/rails g controller Comments
app/controllers/comments_controller.rb
class CommentsController < ApplicationController
def create
@post = Post.find(params[:post_id])
@comment = Comment.create! content: params[:comment][:content],
post: @post, user: @current_user
end
end
touch app/views/comments/create.js.erb
(() => {
const el = document.getElementById('comments')
el.insertAdjacentHTML('beforeend', '<%=j render @comment %>')
const new_comment = document.getElementById('new_comment')
new_comment.outerHTML = '<%=j render "comments/new", post: @post %>'
})()
app/views/comments/_comment.html.erb
<article id="comment-<%= comment.id %>">
<h3>Comment by <%= comment.user.name %></h3>
<p><%= comment.content %>
<%= link_to 'Destroy', post_comment_path(comment.post, comment), method: :delete, data: { confirm: 'Are you sure?' }, remote: true %>
</p>
</article>
コメントを投稿できることを確認します。
bin/rails s
Commentの削除
app/controllers/comments_controller.rb
def destroy
@comment = Comment.find(params[:id])
@comment.destroy
end
touch app/views/comments/destroy.js.erb
(() => {
const el = document.getElementById('comment-<%= @comment.id %>')
el.remove()
})()
コメントを削除できることを確認します。
bin/rails s
以上です。
この記事が気に入ったらサポートをしてみませんか?