CRUD Ownership of Items/Microposts in Rails App

2019-08-16 14:23发布

问题:

I have a simple rails app where users can create 'items', but on the master index page that lists all the items, there are 'Show, Edit, and Delete' links next to each 'item'. I understand that this is due to the fact that I used scaffolding to accomplish the items, but I'd like to make sure that people can only edit the ones that they created. This logic is a little above my head at the moment, as, like I've said before, am totally new to rails.

User Controller:

class UsersController < ApplicationController
  def show
    @user = User.find_by_username(params[:id])
  end
  def index
    @user = User.find(:all)
  end
end

Master Item View:

<div class="well">
  <h1>All Items</h1>
    <table>
  <tr>
    <th>Title</th>
    <th>Details</th>
    <th>Inquire</th>
    <th></th>
    <th></th>
    <th></th>
  </tr>
<% @items.each do |item| %>
  <tr>
    <td><%= link_to item.title, item_path(item) %></td>
    <td><%= item.content %></td>
    <td><%= mail_to item.email, "Inquire", :cc => "michaelomchenry@gmail.com",
                 :subject => "OverFlow Inquiry Regarding " + item.title %></td>
    <td><%= link_to 'Show', item %></td>
    <td><%= link_to 'Edit', edit_item_path(item) %></td>
    <td><%= link_to 'Destroy', item, confirm: 'Are you sure?', method: :delete %></td>
  </tr>
<% end %>
  </table>

<br />
<%= link_to 'New Item', new_item_path %>
</div>

Item Model:

class Item < ActiveRecord::Base
  attr_accessible :content, :user_id, :title
  validates :content, :length => { :maximum => 140 }
  belongs_to :user
  delegate :email, to: :user
end

回答1:

There is a lot of stuff there. First of all, to be able to filter the items (or the actions) based on the user, you need to know who is logged at the time, and so enable users to login. This could be done for example using Devise, an authorization gem for Rails. Devise is largely used and well documented.

Once Devise is setup, you can check whether the user is logged (for example using a before_filter), and Devise will create a "current_user" variable for you to use (this is shown in Devise tutorial). You can then use it to filter your item lists with something like :

editable_items = current_user.items

And then use the editable_items on your view. I would advise you to go read the Devise tutorial as what you are doing is a quite common and well documented task.



回答2:

I would comment if I could, but I feel that this must be said in reference to the answer posted by @momchenr (answering their own question) as a follow up to the chosen answer.

@momcher wrote:

I ended up doing this:

<% if item.email == current_user.email %>

and it worked... is that ok?

Probably not. But that depends on how your system is set up. If users can edit their email addresses and/or email addresses aren't forced to be unique, they may be able to gain editing access to another user's "items" by changing their email address temporarily or just signing up as a new user with a known user's email address.

Even if you never display email addresses of users in your application, there is an inherent vulnerability when you leave that much of the authentication process in a user-provided field.

Not knowing exactly how things are set up in Devise—only based on the info you have provided—I'd try the following:

These two might be are a touch slower depending on the state of ActiveRecord when called

  • <% if item.user == current_user %>
  • <% if item.user.id == current_user.id %>

This one ought to be a touch faster since you are not getting the user object from the item object (you are just pulling directly from the user_id method of the user object)

  • <% if item.user_id == current_user.id %>

No matter if I am right or wrong in my guesses at speed, this is generally a better solution than the one you said works for you. Since the user's ID is never under their control directly—unless there are major holes in your code—they cannot easily pose as other users.



回答3:

I ended up doing this:

<% if item.email == current_user.email %>

and it worked... is that ok?