学生向けプログラミング入門

学生向けにプログラミングを解説。Java、C++、Ruby、PHP、データベース

Ruby on RailsでWebアプリケーション開発その33 アクセス制限の実装

<<前  [TOP]  次>>


Railsのフィルタ機能を使い商品登録ページへのアクセス制限を実装していきます。


まずは「app/controllers」フォルダにある「application_controller.rb」ファイルの編集です。


【app/controllers/application_controller.rb】

class ApplicationController < ActionController::Base

  before_filter :authorize

  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :exception

	private
	def current_cart

		Cart.find(session[:cart_id])

		rescue ActiveRecord::RecordNotFound
			cart = Cart.create
			session[:cart_id] = cart.id
			cart
	end

  protected

    def authorize
        unless User.find_by_id(session[:user_id])
          redirect_to login_url, notice: "ログインして下さい。"
        end
    end

end

まず最初に「before_filter :authorize」として、アプリケーションのすべてのアクションの前にauthorize()が呼び出されるようにしています。
「authorize()」の記述は一番最後とし、「protected」にしています。

protected

def authorize
        unless User.find_by_id(session[:user_id])
          redirect_to login_url, notice: "ログインして下さい。"
        end
end



このままだとすべてのページにアクセス制限がかかってしまうので、「market」「sessions」「carts」「line_items」「orders」の各コントローラに「skip_before_filter」という除外の呼び出しを追加します。


【app/controllers/market_controller.rb】

class MarketController < ApplicationController
  skip_before_filter :authorize

  def index

	@goods = Good.select_shop
	
	respond_to do |format|
 		format.html
		format.json { render :xml => @good }
	end
  end

end



【app/controllers/sessions_controller.rb】

class SessionsController < ApplicationController
  skip_before_filter :authorize

  def new
  end

  def create
	user = User.find_by_name(params[:name])
	if user and user.authenticate(params[:password])
		session[:user_id] = user.id
		redirect_to admin_url
	else
		redirect_to login_url, alert: '無効なユーザ/パスワードの組み合わせです。'
	end
  end

  def destroy
	session[:user_id] = nil
	redirect_to login_url, alert: "ログアウトしました。"
  end
end



【app/controllers/carts_controller.rb】

class CartsController < ApplicationController

    before_action :set_cart, only: [:show, :edit, :update, :destroy]

    before_action :set_cart, only: [:show, :edit, :update, :destroy]

  # GET /carts
  # GET /carts.json
  def index
    @carts = Cart.all
  end

  # GET /carts/1
  # GET /carts/1.json
  def show

	begin
		@cart = Cart.find(params[:id])

	rescue ActiveRecord::RecordNotFound
		logger.error "無効なカート#{params[:id]}にアクセスしようとしました。"
		redirect_to market_url, notice: '無効なアクセスです。'
	else
		respond_to do |format|
			format.html
			format.json { render json: @cart }
		end
	end
  end

  # GET /carts/new
  def new
    @cart = Cart.new
  end

  # GET /carts/1/edit
  def edit
  end

  # POST /carts
  # POST /carts.json
  def create
    @cart = Cart.new(cart_params)

    respond_to do |format|
      if @cart.save
        format.html { redirect_to @cart, notice: 'Cart was successfully created.' }
        format.json { render :show, status: :created, location: @cart }
      else
        format.html { render :new }
        format.json { render json: @cart.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /carts/1
  # PATCH/PUT /carts/1.json
  def update
    respond_to do |format|
      if @cart.update(cart_params)
        format.html { redirect_to @cart, notice: 'Cart was successfully updated.' }
        format.json { render :show, status: :ok, location: @cart }
      else
        format.html { render :edit }
        format.json { render json: @cart.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /carts/1
  # DELETE /carts/1.json
  def destroy

    @cart = current_cart
    @cart.destroy
    session[:cart_id] = nil
    respond_to do |format|
      format.html { redirect_to market_url, notice: 'カートが空になりました。' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_cart
      @cart = Cart.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def cart_params
      params.fetch(:cart, {})
    end
end

「skip_before_filter :authorize」の対象を「:show」「:create」「:update」「:destroy」に限定しています。


【app/controllers/line_items_controller.rb】

class LineItemsController < ApplicationController

    skip_before_filter :authorize, only:  [:create, :destroy]

    before_action :set_line_item, only: [:show, :edit, :update, :destroy]

  # GET /line_items
  # GET /line_items.json
  def index
    @line_items = LineItem.all
  end

  # GET /line_items/1
  # GET /line_items/1.json
  def show
  end

  # GET /line_items/new
  def new
    @line_item = LineItem.new
  end

  # GET /line_items/1/edit
  def edit
  end

  # POST /line_items
  # POST /line_items.json
  def create

	@cart = current_cart

	good = Good.find(params[:good_id])

	@line_item = @cart.add_good(good.id)

    respond_to do |format|
      if @line_item.save
        format.html { redirect_to @line_item.cart, notice: 'カートに商品が追加されました。' }
        format.json { render :show, status: :created, location: @line_item }
      else
        format.html { render :new }
        format.json { render json: @line_item.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /line_items/1
  # PATCH/PUT /line_items/1.json
  def update
    respond_to do |format|
      if @line_item.update(line_item_params)
        format.html { redirect_to @line_item, notice: 'Line item was successfully updated.' }
        format.json { render :show, status: :ok, location: @line_item }
      else
        format.html { render :edit }
        format.json { render json: @line_item.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /line_items/1
  # DELETE /line_items/1.json
  def destroy
    @line_item.destroy

    respond_to do |format|
      format.html { redirect_to cart_url(@line_item.cart_id), notice: '商品をカートから削除しました。' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_line_item
      @line_item = LineItem.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def line_item_params
      params.require(:line_item).permit(:good_id, :cart_id)
    end
end

「skip_before_filter :authorize」の対象を「:create」「:destroy」に限定しています。


【app/controllers/orders_controller.rb】

class OrdersController < ApplicationController

    skip_before_filter :authorize, only: [:new, :create]

    before_action :set_order, only: [:show, :edit, :update, :destroy]

  # GET /orders
  # GET /orders.json
  def index

    @orders = Order.paginate :page=>params[:page], :per_page =>10

	respond_to do |format|
		format.html
		format.json { render json: @orders }
	end

  end

  # GET /orders/1
  # GET /orders/1.json
  def show
  end

  # GET /orders/new
  def new
	@cart = current_cart
	if @cart.line_items.empty?
		redirect_to market_url, notice: 'カートは空です。'
		return
	end

	@order = Order.new

	respond_to do |format|
		format.html
		format.json { render json: @order }
	end
  end

  # GET /orders/1/edit
  def edit
  end

  # POST /orders
  # POST /orders.json
  def create
    @order = Order.new(order_params)
    @order.add_items(current_cart)

    respond_to do |format|
      if @order.save
	Cart.destroy(session[:cart_id])
	session[:cart_id] = nil
        format.html { redirect_to market_url, notice: 'ご注文ありがとうございました。' }
        format.json { render json: @order, status: :created, location: @order }
      else
        format.html { render :new }
        format.json { render json: @order.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /orders/1
  # PATCH/PUT /orders/1.json
  def update
    respond_to do |format|
      if @order.update(order_params)
        format.html { redirect_to @order, notice: '注文情報を更新しました。' }
        format.json { render :show, status: :ok, location: @order }
      else
        format.html { render :edit }
        format.json { render json: @order.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /orders/1
  # DELETE /orders/1.json
  def destroy
    @order.destroy
    respond_to do |format|
      format.html { redirect_to orders_url, notice: 'Order was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_order
      @order = Order.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def order_params
      params.require(:order).permit(:name, :address, :email, :tel_number, :pay_type)
    end
end

「skip_before_filter :authorize」の対象を「:new」「:create」に限定しています。


管理ビューに各リンクを追加します。


【app/views/admin/index.html.erb】

<h1>管理者</h1>
<br>
<%= button_to 'ログアウト', logout_path, method: :delete   %>
<br>
<h2>ログインしています。</h2>
<p>現在時刻:<%= Time.new %></p>
<br>
 <%= link_to '注文を見る', orders_path, class: 'btn' %><span>  </span><%= link_to '商品登録',goods_path, class: 'btn' %><span>  </span><%= link_to 'ユーザ管理', users_path, class: 'btn' %>



では「http://localhost:3000/goods」にアクセスしてみます。
f:id:MrRadiology:20180307105037p:plain
このようにログインページが表示されました。
ログインします。
f:id:MrRadiology:20180307112806p:plain
各ページへアクセス出来ます。
ではログアウトします。
f:id:MrRadiology:20180307112911p:plain
http://localhost:3000/goods」にアクセス出来なくなりました。


<<前  [TOP]  次>>