Cancan non mostra gli elementi della vista autorizzata
-
26-09-2019 - |
Domanda
Sto cercando di ottenere un'autenticazione/autorizzazione di base con devise/cancan con Rails.Invece di utilizzare ruoli come lo screencast di Ryan B e altri esempi in giro, sto cercando di fare qualcosa di semplice:
1 - Un utente può accedere
2 - Un utente può solo modificare/distruggere i propri articoli (nessun ruolo, o hai effettuato l'accesso e puoi creare nuovi articoli e modificare/distruggere i tuoi oppure sei disconnesso e puoi solo vedere gli articoli ed effettuare l'accesso)
Sto usando devise per la prima parte e funziona bene, ma non riesco a far funzionare la seconda parte con CanCan.I link di modifica e distruzione degli articoli non vengono visualizzati quando hai effettuato l'accesso e l'URL diretto (ad es./articles/3/edit) consente comunque anche se l'articolo è per un altro utente.
Mio ability.rb
È
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user
if user.nil?
can :read, :all
else
# can :manage, :all #test - with this, all the edit/destroy links appear
can :manage, Article, :user_id == user
end
end
end
articles_controller.rb
:
class ArticlesController < ApplicationController
before_filter :authenticate_user!, :except => [:index, :show] # for Devise
load_and_authorize_resource
# GET /articles
# GET /articles.xml
def index
@articles = Article.all
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => @articles }
end
end
# GET /articles/1
# GET /articles/1.xml
def show
@article = Article.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => @article }
end
end
# GET /articles/new
# GET /articles/new.xml
def new
@article = Article.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => @article }
end
end
# GET /articles/1/edit
def edit
@article = Article.find(params[:id])
end
# POST /articles
# POST /articles.xml
def create
@article = Article.new(params[:article])
@article.user = current_user
respond_to do |format|
if @article.save
format.html { redirect_to(articles_path, :notice => 'Article was successfully created.') }
format.xml { render :xml => articles_path, :status => :created, :location => articles_path }
else
format.html { render :action => "new" }
format.xml { render :xml => @article.errors, :status => :unprocessable_entity }
end
end
end
# PUT /articles/1
# PUT /articles/1.xml
def update
@article = Article.find(params[:id])
respond_to do |format|
if @article.update_attributes(params[:article])
format.html { redirect_to(@article, :notice => 'Article was successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => @article.errors, :status => :unprocessable_entity }
end
end
end
# DELETE /articles/1
# DELETE /articles/1.xml
def destroy
@article = Article.find(params[:id])
@article.destroy
respond_to do |format|
format.html { redirect_to(articles_url) }
format.xml { head :ok }
end
end
end
e la vista parziale che elenca gli articoli _article_list.html.erb
:
<table>
<tr>
<th>Title</th>
<th>Description</th>
<th>User</th>
<th></th>
<th></th>
<th></th>
</tr>
<% @articles.each do |article| %>
<tr>
<td><%= article.title %></td>
<td><%= article.description %></td>
<td><%= article.user_id %></td>
<td><%= link_to 'Show', article %></td>
<% if can? :update, @article %>
<td><%= link_to 'Edit', edit_article_path(article) %></td>
<% end %>
<% if can? :destroy, @article %>
<td><%= link_to 'Destroy', article, :confirm => 'Are you sure?', :method => :delete %></td>
<% end%>
</tr>
<% end %>
</table>
Con questa configurazione, i collegamenti di modifica/distruzione nella vista non vengono visualizzati a meno che non sia presente una coperta can :manage, :all
, Anche can :manage, Article
non funziona.Come ho già detto in precedenza, inoltre, non limita le azioni effettive poiché puoi collegarti direttamente alla modifica di un articolo e ciò lo consente.
Non sono sicuro di cosa sto facendo di sbagliato qui.Sarebbe fantastico ricevere aiuto.
grazie in anticipo
Giasone
Soluzione
Sono riuscito a risolvere il mio problema.Ho ripristinato il mio ambiente (rvm - ho resinato le gemme e i set di gemme - ruby 1.9.2 e rails 3.0.0) e ho modificato parte del codice e tutti i problemi che avevo sono scomparsi (loop di reindirizzamento, visualizzazione degli elementi che non cambiavano in base alla registrazione in, azioni del titolare non autorizzate sono ancora consentite).Ho incollato ability.rb
, articles_controller.rb
, E _article_list.html.erb
.
ability.rb
:
class Ability
include CanCan::Ability
def initialize(user)
if user
can :create, Article
can :read, :all
can :update, Article, :user_id => user.id
can :delete, Article, :user_id => user.id
else
can :read, :all
end
end
end
Immagino che ora abbia senso, ma poiché solo l'aggiornamento e l'eliminazione avrebbero dovuto riguardare gli articoli dell'utente corrente, ho suddiviso gli elementi CRUD per essere specifici.
articles_controller.rb
class ArticlesController < ApplicationController
before_filter :authenticate_user!, :except => [:index, :show]
# load_and_authorize_resource # RESTful automated CanCam authorization - excludes non RESTful
# GET /articles
# GET /articles.xml
def index
@articles = Article.all
authorize! :read, @articles
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => @articles }
end
end
# GET /articles/1
# GET /articles/1.xml
def show
@article = Article.find(params[:id])
authorize! :read, @article
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => @article }
end
end
# GET /articles/new
# GET /articles/new.xml
def new
@article = Article.new
authorize! :create, @article
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => @article }
end
end
# GET /articles/1/edit
def edit
@article = Article.find(params[:id])
authorize! :update, @article
end
# POST /articles
# POST /articles.xml
def create
@article = Article.new(params[:article])
@article.user = current_user
authorize! :create, @article
respond_to do |format|
if @article.save
format.html { redirect_to(articles_path, :notice => 'Article was successfully created.') }
format.xml { render :xml => articles_path, :status => :created, :location => articles_path }
else
format.html { render :action => "new" }
format.xml { render :xml => @article.errors, :status => :unprocessable_entity }
end
end
end
# PUT /articles/1
# PUT /articles/1.xml
def update
@article = Article.find(params[:id])
authorize! :update, @article
respond_to do |format|
if @article.update_attributes(params[:article])
format.html { redirect_to(@article, :notice => 'Article was successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => @article.errors, :status => :unprocessable_entity }
end
end
end
# DELETE /articles/1
# DELETE /articles/1.xml
def destroy
@article = Article.find(params[:id])
@article.destroy
authorize! :delete, @article
respond_to do |format|
format.html { redirect_to(articles_url) }
format.xml { head :ok }
end
end
def by
@user = User.find(params[:id])
@articles = @user.articles
authorize! :read, @articles
end
end
load_and_authorize_resource
funziona ma ho messo l'autorizzazione specifica!linee in ogni azione del controller poiché ho un'azione extra in basso.Entrambi ora funzionano.
Ho aggiornato il riferimento a @article in article per fare riferimento all'articolo corrente nell'elenco in _article_list.html.rb
:
<table>
<tr>
<th>Title</th>
<th>Description</th>
<th>User</th>
<th></th>
<th></th>
<th></th>
</tr>
<% @articles.each do |article| %>
<tr>
<td><%= article.title %></td>
<td><%= article.description %></td>
<td><%= article.user_id %></td>
<td><%= link_to 'Show', article %></td>
<% if can? :update, article %>
<td><%= link_to 'Edit', edit_article_path(article) %></td>
<% end %>
<% if can? :delete, article %>
<td><%= link_to 'Destroy', article, :confirm => 'Are you sure?', :method => :delete %></td>
<% end %>
</tr>
<% end %>
</table>
Tutto funziona adesso.Grazie per l'aiuto qui e spero che questo possa aiutare qualcun altro se dovesse riscontrare questo problema.
Altri suggerimenti
La vostra condizione per corrispondenza un ID utente non è giusto. Dovrebbe essere:
can :manage, Article, :user_id => user.id
L'attributo che si desidera controllare è mappato il valore che si desidera controllare contro.
Inoltre, si sta verificando per user.nil?
quando non può essere pari a zero, perché hai appena inizializzato esso. (Probabilmente un sintomo di avere un sacco di cose provato!)
Il vostro lavoro trucco? Se si rimuove il commento dalla lattina: gestire: tutto linea sarà un utente in grado di modificare la sua / il suo posto (insieme di tutti gli altri, naturalmente)
?Hai provato cambiando, in grado di: gestire, articolo,: user_id == all'utente di
can :manage, Article do |article|
article.try(:user) == user
non sono mai stato in grado di ottenere un carico di autorizzare al lavoro-anche se ho il sospetto che stavo facendo qualcosa di sbagliato. Per impedire a qualcuno di accedere al URL direttamente, in azione di modifica del tuo articolo, prova ad aggiungere questo
unauthorized! if cannot? :edit, @article