I have the following method to check if a user has admin access.
def has_admin_access?(user)
user.present? && gym_users.where(:role_id => [3, 4]).where(['user_id = ? AND date_ended IS NULL', user.id]).any?
end
The problem comes when I want to call this multiple times on a page. How can I do this so that I set a private value and only make the database call the first time?
You can just store the result in a hash, and if you look up the same user again return the result from the hash. Like this:
def has_admin_access?(user)
#admin_hash ||= {}
if (!#admin_hash.include?(user))
#admin_hash[user] = user.present? && gym_users.where(:role_id => [3, 4]).where(['user_id = ? AND date_ended IS NULL', user.id]).any?
end
#admin_hash[user]
end
Try:
extend ActiveSupport::Memoizable
memoize :has_admin_access?
more information
Related
I have the following controller in Rails:
class FooController < ApplicationController
def delete_foo(bar):
Foo.destroy_all("foo = '#{#bar}'")
Is
Foo.destroy_all("foo = ?", #bar)
always valid?
destroy_all works on a relation. Why not do
Foo.where(foo: bar).destroy_all
Foo.destroy_all("foo = ?", #bar), This is invalid.
From apidoc, we will find:
destroy_all(conditions = nil) public
destroy_all method only accepts a single argument, the argument can be a string, array, or hash. You cannot pass two arguments.
So you can write like this:
Foo.destroy_all("foo = #{#bar}")
Foo.destroy_all(foo: #bar)
Foo.where(foo: #bar).destroy_all
Goal: two users root and user. Root can access everything via web-interface, but user should see only some parts of the menus.
One option would be to pass "sysauth" option to every module in question. That is not very practical, because the user would see every menu entry and would get login page for every menu he is not allowed to.
My idea is to figure out who is logged on and then do nothing in the index() function of each restricted module. So far I couldn't find such a function in LuCI API (http://luci.subsignal.org/api/luci/), that would return a current logged user.
I know how to add additional users in OpenWrt/LuCI (https://forum.openwrt.org/viewtopic.php?pid=163013#p163013). But it is only a part of the solution.
Any idea, how to achieve my goal?
I ended up creating a Lua function like described here: http://lua-users.org/wiki/SaveTableToFile, to find and remove unneeded keys from the table.
function remove_idx( tbl, index )
-- initiate variables for save procedure
local tables,lookup = { tbl },{ [tbl] = 1 }
for idx,t in ipairs( tables ) do
local thandled = {}
for i,v in ipairs( t ) do
thandled[i] = true
local stype = type( v )
-- only handle value
if stype == "table" then
if not lookup[v] then
table.insert( tables, v )
lookup[v] = #tables
end
else
if i == index then
t[i] = nil
return
end
end
end
for i,v in pairs( t ) do
-- escape handled values
if (not thandled[i]) then
local flag = 0
local stype = type( i )
-- handle index
if stype == "table" then
if not lookup[i] then
table.insert( tables,i )
lookup[i] = #tables
end
else
flag = 1
if i == index then
t[i] = nil
return
end
end
if flag == 1 then
stype = type( v )
-- handle value
if stype == "table" then
if not lookup[v] then
table.insert( tables,v )
lookup[v] = #tables
end
else
if i == index then
t[i] = nil
return
end
end
end
end
end
end
end
And then inserted my user check and page delete after in libs/web/luasrc/dispatcher.lua dispatch():
if c and c.index then
local tpl = require "luci.template"
if util.copcall(tpl.render, "indexer", {}) then
return true
end
end
That's how I remove unneeded pages depending on who is logged in:
if ctx.authuser == "user" then
remove_idx(ctx.tree, "packages")
remove_idx(ctx.tree, "leds")
end
It is a little bit quick and dirty, but it works. Please note, that direct access by
manipulating the URL is still possible.
Update
LuCI2 will provide ACL support und multi-user environment: http://git.openwrt.org/?p=project/luci2/ui.git;a%3Dsummary
If you'd like to create multiple OpenWRT Luci users with varying access, you can following these steps:
Create a local user account
Add the user to the RCP configuration and define access level
See sample excerpt from /etc/config/rpcd config below:
config login
option username 'adminuser'
option password '$p$adminuser'
list read '*'
list write '*'
config login
option username 'readonlyuser'
option password '$p$readonlyuser'
list read '*'
This also works if you're obtaining an authentication token for JSON-RPC calls to Luci.
I have the following code in my Rails 3 application:
def like
#suggestion = Suggestion.find(params[:id])
Suggestion.update_all("votes = (votes + 1)")
redirect_to suggestions_url
end
def dislike
#suggestion = Suggestion.find(params[:id])
Suggestion.update_all("votes = (votes - 1)")
redirect_to suggestions_url
end
It's working, but rather than updating the current suggestion it's updating them all. So I changed it to:
def like
#suggestion = Suggestion.find(params[:id])
#suggestion.update_all("votes = (votes + 1)")
redirect_to suggestions_url
end
def dislike
#suggestion = Suggestion.find(params[:id])
#suggestion.update_all("votes = (votes - 1)")
redirect_to suggestions_url
end
but then I get:
undefined method `update_all' for #<Suggestion:0x007f87c2b918a0>
So then I tried #suggestion.update_attribute(:votes, '1') but that resets the value to 1 instead of incrementing it.
What's the correct way to achieve this? I just want the integer (votes) of the current suggestion to increment/decrease by 1 on each save.
I've also tried the following with no luck:
def like
#suggestion = Suggestion.find(params[:id])
#suggestion.increment(:votes)
redirect_to suggestions_url
end
This seems more suitable in the model. I suggest creating a like method inside the model like so:
def like
self.increment!(:votes)
end
Now you can do something like this:
#suggestion = Suggestion.find(params[:id])
#suggestion.like
Note: increment!, with the exclamation point also performs the save action
A couple things. It sounds like what you want is a controller action that increments an attribute by one. You were probably closest with the code
#suggestion.update_attribute(:votes, '1')
If you check the documentation for that method, it sets the value of the attribute votes to the second arguement, the string '1', on the object, #suggestion, and its corresponding row in the database. Instead of setting it to '1', you want to set it to the incremented value:
#suggestion.update_attribute(:votes, #suggestion.votes + 1)
Ethan suggested using the convenience method, increment!, which works just the same.
Now, if you wanted to actually auto-increment each time the object gets saved (as in something else about the object gets altered, you'd want to use the :before_save callback with increment without the bang.
I am using Mocha, and I want to stub a method which does not have a return value.
It looks something like this
def some_method
increment_counter+=1
database_model.update_attributes(:column => "something")
end
how do I test teh functionality of this method, and see if the database model is updated?
def some_method
increment_counter+=1
database_model.update_attributes(:column => "something")
updated_database_model = Model.find(database_model.id)
updated_database_model.column.should == "something"
end
Sorry in advance for this incredibly simple question, but what is the best way to set a variable while also checking a condition. For example, I have:
#friends = []
#user.facebook_friends.each do |key,value|
if test = Authorization.includes(:user).find_by_uid(key) != nil
#friends << {"name" => test.user.name, "facebook_image_url" => test.user.facebook_image_url}
end
end
I am trying to pull in the user records when I pull in the authorization record, so as to minimize my database queries. I know that I can't write
test = Authorization.includes(:user).find_by_uid(key) != nil
in order to set the test variable. What is the best way to write this code so that it is functional?
You just need parens:
(test = Authorization.includes(:user).find_by_uid(key)) != nil
Also here is a more rails way to do it:
unless (test = Authorization.includes(:user).find_by_uid(key)).nil?
#friends << {"name" => test.user.name, "facebook_image_url" => test.user.facebook_image_url}
end