ruby on rails仅限用户使用特定数据

时间:2012-04-19 01:00:08

标签: ruby-on-rails ruby ruby-on-rails-3

我想限制用户只能查看和编辑来自公寓的数据。我已将他们的apartment_id保存在会话[:apartment_id]中。所以,我有CRUD,我想限制用户不能进行/ data / ID / edit只能更改ID然后编辑数据。有没有一种很好的方法可以做到这一点,比方说,通过一些范围,或者我必须在每个操作中验证控制器中的所有内容。 先感谢您。 Dorijan

编辑: 这个更详细: 假设在执行/数据时有一个用户列表,当你想要查看某个具有ID的用户的特定数据时,你会去/ data / ID example / data / 27。 在我的数据库中,对于模型数据,我得到了行apartment_id,它告诉用户属于哪个公寓。

现在,我想基于会话数据限制某些用户的视图。例如,当用户登录时,他得到了会话[:apartment_id]。

所以,我希望能够限制用户无法访问例如user_id = 34的/ data / 34,其中apartment_id与session [:apartment_id]不同。

另外,当用户访问/数据时只显示用户的明显。

我知道我可以在每个控制器中执行此操作,因为每种方法都可以检查这一点,但是我可以在模型中的某个位置执行此操作吗? 谢谢

3 个答案:

答案 0 :(得分:2)

向您的Rails应用添加行级安全性 如果您正在使用数据库构建Web应用程序,则可能需要多个用户,这意味着要添加行级安全性和身份验证。

Rails帮助一个名为Devise的酷炫宝石。 Devise创建一个User表和视图,通过会话对Web应用程序进行身份验证,然后您可以为每个视图添加身份验证,以确保您有一个有效的会话来查看该视图。

这一切都很好,但是没有解决我的另一个问题,那就是用户限制数据库中的数据。所以我选择使用Devise User模型,特别是id字段,并由其他数据库表改变以包含id字段(我称之为user_id)。这一切都适用于您随后调整Rails应用程序的其余部分,如模型调用,以使用会话user_id作为每个SQL查询的一部分。让我来解释一下基本步骤,这些步骤有一些细节,但你需要即兴发挥你的情况。

我眼中的过程分为特定于Devise的步骤和行级安全步骤。

设计步骤

为您的Rails项目添加设计

    add devise gem to gem file

    gem ‘devise’

    bundle install



rails generate devise:install

(安装到rails应用程序 - 在app目录根目录中)

rails g devise:views

(可选步骤:这会复制视图,因此我们可以自定义和设置样式)

rails generate devise User

(创建用户模型)

bundle exec rake db:migrate

(创建表 - 注意您需要yml中的权限才能更改数据库结构)

与设计相关的剩余步骤

向application.html.erb添加一个top div,检查用户是否已登录,并显示登录ID或新用户和登录链接

<div class=”top”>

<p class=”notice”><%= notice %></p>

<p class=”alert”><%= alert %></p>

<p>

<% if user_signed_in? %>

  Logged in as <strong><%= current_user.email %></strong>.

  <%= link_to ‘Edit profile’, edit_user_registration_path %> |

  <%= link_to “Logout”, destroy_user_session_path, method: :delete  %>

<% else %>

  <%= link_to “Sign up”, new_user_registration_path  %> |

  <%= link_to “Login”, new_user_session_path %>

<% end %>

</div>

创建了一个“访客”控制器和视图,以显示未登录时 - 还更新routes.rb以使其成为根目录 - 即,当有人第一次访问您的网站时,您应该将它们带到访客控制器,而不是数据!你还没有会话。

更新了访客/根控制器,特别是,如果用户已登录,则转到登录控制器的索引操作

  if user_signed_in?

    redirect_to :controller=>’home’, :action=> ‘index’

  end

在所有其他数据/登录控制器中,在操作之前将以下内容添加到控制器的顶部:这将确保没有人可以使用URL路径登陆页面而不进行身份验证。

before_filter :authenticate_user!

行级步骤

使用user_id列更改要使用行级安全性“RLS”的表。

mysql> ALTER TABLE mytable ADD COLUMN user_id VARCHAR(255) AFTER id;

使用users表中的有效user_id更新表(这假设您已经创建了一个具有注册表单的用户。或者只使用1,因为它出现Devise在1处开始第一个用户ID)

mysql> UPDATE mytable SET user_id = ( SELECT id FROM users WHERE email = ‘mememe@me.com’ );

处理将user_id添加到表插入

在数据/登录控制器CREATE操作中,更新参数对象中的user_id字段。

def create

params[:mytable][:user_id] = current_user.id

…

end

通过将user_id作为参数传递来处理选择/查询

在data / loggedin模型中,将user_id传递给新的查询范围,然后将该新范围与其他范围合并(确保将user_id传递到其他范围;还有其他方法可以执行此操作,但我喜欢范围) :

scope :my, -> (user_id) { where(“user_id = ?”, user_id) }

scope :mylovelyquery, -> (user_id) { my(user_id).where(:mylovelyselectioncriteria=>”A”).order(“mysortfield”)  }

在数据/记录控制器中,更改索引操作以获取current_user.id并将其传递给您创建的ActiveRecord范围。这个步骤是乏味的,可以经常完成 - 寻找任何控制器索引或执行SELET的任何控制器操作 - 需要RLS!这也适用于Ajax调用。

def index

@user_id = current_user.id

@mytables = Mytable.my(@user_id).order(mylovelysortfield DESC”)

end

经验教训

在做任何检索数据库之前,可能最让我感到困惑的是忘记获取current_user.id。

答案 1 :(得分:1)

如果您的用户有很多公寓,那么通常您可以在控制器中执行此操作:

def edit
  current_user.apartments.find(params[:id])
end

这只会找到属于当前用户的公寓。

更新

看起来你没有current_user对象......所以:

def edit 
  @apartment = Apartment.find(params[:id])
  redirect_to root_path, error: "You do not have access for this apartment"
end

答案 2 :(得分:0)

您可以对要在控制器中限制的任何操作使用before_filter。以下是关于这个主题的一些阅读:http://guides.rubyonrails.org/action_controller_overview.html#filters