CanCan在我的rails应用程序中定义了各种角色。我最近实现了jQueryUI自动完成,它运行得很好。问题是,当我提交表单时,模型中出现的find_by_name可以找到不属于current_user的记录。我的观点如下:
<strong><%= f.label :inventory_name, "Material" %></strong>
<%= f.text_field :inventory_name, :class => "inputbox" %><br>
我的jQuery看起来像:
jQuery("input[id$=_inventory_name]").autocomplete({
source: '/ajax/inventory',
minLength: 2
});
然后我有一个ajax控制器,它可以做正确的事情:
def inventory
inventory = Inventory.accessible_by(current_ability)
if params[:term]
like= "%".concat(params[:term].concat("%"))
names = inventory.where("name LIKE ?", like)
else
names = inventory
end
list = names.map {|u| Hash[ :id => u.id, :label => u.name, :name => u.name]}
render :json => list
end
但我的模型没有:
def inventory_name=(name)
inventory = Inventory.find_by_name(name)
if inventory
self.inventory_id = inventory.id
else
errors[:inventory_name] << "Invalid name entered"
end
end
def inventory_name
Inventory.find(inventory_id).name if inventory_id
end
find_by_name将返回它找到的第一个匹配项,而不管谁拥有它。理想情况下,我想更改:
inventory = Inventory.find_by_name(name)
至
inventory = Inventory.accessible_by(current_ability).find_by_name(name)
但这违反了MVC的原则,更不用说模型无法访问current_ability、current_user等。所以我的问题是,我如何将这个逻辑转移到我的控制器中,在那里我可以访问这些东西?我似乎无法理解它:(
我认为您所需要做的就是让控制器中的创建和更新操作检查Inventory.accessible_by(current_ability)
。
我最终需要前后过滤器:
after_filter :save_new_project_inventory, :only => [:create]
before_filter :update_project_inventory, :only => [:create, :update]
private
def save_new_project_inventory
# do this in an after filter so that
# we will have a project.id
@project_inventories.each { |key, value|
value[:project_id] = @project.id
ProjectInventory.create!(value)
}
end
def update_project_inventory
@project_inventories = {}
params[:project][:project_inventories_attributes].each { |key, value|
if value[:_destroy] != "false"
project_inventory = ProjectInventory.find(value[:id])
project_inventory.delete
else
if value[:id]
project_inventory = ProjectInventory.find(value[:id])
project_inventory.inventory_id = inventory_name(value[:inventory_name])
project_inventory.save
else
if @project.nil?
# can't save here because we need a project.id that we
# won't have until after we save, so finish up in the
# after filter
@project_inventories[key] = {
:inventory_id => inventory_name(value[:inventory_name])
}
else
project_inventory = ProjectInventory.new
project_inventory.inventory_id = inventory_name(value[:inventory_name])
project_inventory.project_id = params[:id]
project_inventory.save
end
end
end
}
params[:project].delete(:project_inventories_attributes)
end
def inventory_name(name)
inventories = Inventory.accessible_by(current_ability)
inventory = inventories.find_by_name(name)
if inventory
inventory.id.to_s
end
end
我不确定这是否是最好的方法,但它有效。
我知道这是旧的,但我遇到了完全相同的问题,直到现在都被难住了。我最终为其他人找到了一个简单得多的解决方案。
在我的例子中,current_user创建了一个作业,该作业需要一个分配给它的客户(一个也属于当前用户的客户)。jQuery UI自动完成用于搜索客户,当然,我只希望属于当前用户的客户可以分配给正在创建的作业,与最初的问题非常相似。我的最终解决方案只是在新作业表单中添加一个user_id的隐藏字段,在调用新操作时填充user_id。
JobsController
def new
@job = current_user.jobs.new(user_id: current_user.id)
end
通过这种方式,在模型中,我们可以用self.user_id(取隐藏字段中的值)获取user_id,然后将其用作查找的搜索标准的一部分。为了可读性,我已将self.user_id分配给变量"user"。
JobModel
def customer_name=(fullname)
user = self.user_id
self.customer = Customer.find_by(fullname: fullname, user_id: user)
end
很简单,现在,除非搜索词(在本例中为fullname)和user_id在Customer模型中都匹配,否则不会返回任何结果,并且用户需要重试,即使Customer模型中存在具有不同user_id的具有相同全名的记录,也不会返回。
希望这能有所帮助。
编辑:记住将user_id添加到允许的参数中。