2013-07-29 18 views
5

ユーザロールに応じてビューの一部を隠そうとしています。Rails 4でユーザ役割が与えられたビューの一部を非表示にする方法

私は管理者だけが商品を破棄できるようにしたいとします。レコードを破壊するから通常のユーザーを防止するためのコントローラのコードのほかに、私は、ビューで次の操作を行います:

<% if current_user.admin? %> 
    <%= link_to 'Delete', product, method: :delete %> 
<% end %> 

以前のコードが動作しますが、それは通常のユーザーに表示することがあり不作為のエラーになりやすいのです実行が許可されていないアクションへのリンク。

また、新しい役割(「モデレータ」など)で商品を削除できることを後で判断すると、削除リンクが表示されているビューを見つけて、モデレータが見ることができるロジックを追加する必要があります。

管理ユーザー(例:プロモーション、ユーザー)のみが削除できるモデルが多数ある場合は、すべてのifのメンテナンスがかなり難しくなります。

もっと良い方法がありますか?たぶんヘルパーなどを使用していますか?私は多分このような何かを探しています:

<%= destroy_link 'Delete', product %> # Only admins can see it 
<%= edit_link 'Edit', promotion %> # Again, only admins see this link 
<%= show_link 'Show', comment %> # Everyone sees this one 

私は私に似ているこれら二つの質問を見つけましたが、それらのどれも私の質問に答えない:

Show and hide based on user role in rails

Ruby on Rails (3) hiding parts of the view

答えて

6

私は強くお勧めしますpundit

これにより、モデルごとに「ポリシー」を作成できます。あなたのProductモデルのためにあなたはあなたがmoderator役割を追加したい、後にした場合、この

<% if policy(@post).delete? %> 
    <%= link_to 'Delete', product, method: :delete %> 
<% end %> 

ような何かを行うだけで変更することができ、あなたの見解では、この

class ProductPolicy < ApplicationPolicy 
    def delete? 
    user.admin? 
    end 
end 

ようになりますProductPolicyを持っているかもしれませんポリシー方法

class ProductPolicy < ApplicationPolicy 
    def delete? 
    user.admin? || user.moderator? 
    end 
end 
+1

[pundit](https://github.com/elabs/pundit)の+1。 "メインストリーム" [CanCan](https:// github。com/ryanb/cancan)は、ビューとコントローラのロジックで明示的に同じように使いやすく、より柔軟になります([rolify](https://github.com/EppO/rolify)とともに使用すると、 )) こちらも強くお勧めします! – CloudRide

+0

これを正しい答えとして選択してください。私は自分の答えが大好きではなかった。 :P –

1

CanCanは、ユーザーロールごとに「能力」を定義できる別の宝石です。 ビューでif can? :delete, @postのようなものを使用して、 ユーザーが特定の投稿を削除できるかどうかを確認できます。

1

私は、IFをビューから移動する方法を考え出しました。まず、私は私のapplication_helper.rbでのlink_toヘルパーをオーバーライドします。

def link_to(text, path, options={}) 
    super(text, path, options) unless options[:admin] and !current_user.admin? 
end 

その後、私はそれを使用する私の見解でよう:

<%= link_to 'Edit Product', product, admin: true, ... %> 

これは、管理リンクを見てから、他のHTMLタグの正規ユーザーを防ぎdivやテーブルなどのコンテンツがある場合は、ifが必要です。

0

CanCanとRoleのgemを使用して、Routeをチェックし、 "current_user"にそのルートに基づいてそのルートにアクセスする権限があるかどうかを確認し、それに基づいて表示/非表示を切り替える方法が必要です。

これにより、ユーザーは物事をクリックして表示されないことがわかります。また、アイテムごとの "if"ロジックを記述して、どのようなロールがどのリストアイテム(定期的に顧客がロール1つのメニュー内のすべての単一のリンクの周りで(変更/洗練されています)(50以上のアイテムを含むブートストラップメニューをhtmlフォーマットでグループにネストしたものなど)、これは非常識です。

if-logicを各メニュー項目の周りに配置する必要がある場合は、Abilityファイルで既に定義した役割/権限をチェックして、すべての項目に同じロジックを使用しましょう。

私たちのメニューリストには、「コントローラ/メソッド」の情報ではなく、ルートヘルパーがあるので、各リンクの「パス」に指定されたコントローラのアクションを実行するユーザーの能力をテストする方法は?

パスのコントローラおよび方法(アクション)を取得するには(私の例では、「users_path」ルートヘルパーを使用)...

Rails.application.routes.recognize_path(app.users_path) 
     => {:controller=>"users", :action=>"index"} 

Rails.application.routes.recognize_path(app.users_path)[:controller] 
     => "users" 
だけでコントローラ名を取得します。

能力は、モデルをそのブレークダウンに使用するので、コントローラ名からモデルに変換します(デフォルト命名が使用されていると仮定して)...

Rails.application.routes.recognize_path(app.users_path)[:controller].classify 
     => "User" 

アクション名だけを取得する

Rails.application.routes.recognize_path(app.users_path)[:action] 
     => "index" 

「可能?この方法は、私たちがこれを取得、各メニュー項目のために、アクションのシンボルが必要であり、モデルの定数:

path_hash = Rails.application.routes.recognize_path(app.users_path) 
    model = path_hash[:controller].classify.constantize 
    action = path_hash[:action].to_sym 

その後CURRENT_USERがそれにアクセスできるかどうかを確認するために、当社の既存付ける機能システムを使用して、我々が通過しなければなりません定数としてのシンボルとモデルとしての行動、そう...

<% if can? action model %> 
     <%= link_to "Users List", users_path %> 
    <% end %> 

今、私たちは再び、今までメニューをいじってなくて、能力ファイルからこのリソースとのリンクを見ることができるユーザーを変更することができます。しかし、このビットクリーナーを作るために、私はアプリ-コントローラにこれを各メニュー項目のルックアップを抽出:

def get_path_parts(path) 
    path_hash = Rails.application.routes.recognize_path(path) 
    model_name = path_hash[:controller].classify.constantize 
    action_name = path_hash[:action].to_sym 
    return [model_name, action_name] 
end 
helper_method :get_path_parts 

を...ので、私は、ビューでこれを行うことができます(私はすべて取り出しましたHTML-書式設定)ここでは、簡略化のためのリンクから:

<% path_parts = get_path_parts(users_path); if can?(path_parts[1], path_parts[0]) %> 
    <%= link_to "Users Listing", users_path %> 
<% end %> 

...と、これがあれば、ラップこれらあたりのメニュー項目を入力して、すべての一日取らない作るために、私は正規表現のキャプチャで検索/置換を使用し、ワイルドカードを使用してメニュー項目リストの各リスト項目を1回のパスで囲みます。

これは理想的なものではありません。私はそれをもっと良くするためにもっとたくさんのことをすることができますが、残りのロール/ CanCanシステムの残りの部分を書く余裕はありません。私はこの部分が誰かを助けることを願っています

関連する問題