Ruby on Rails - class caching? - ruby-on-rails

I read an article here and I used the principles found there to write a administration check for my controllers. Basically it checks to see what controller you're in and then I create an array saying if this person as permission to see that controller, than find, pass it on.
The author of the article said that readers shouldn't use the example code as it was flawed and that they should use his plugin (which of course is outdated now). And he said
"there are some issues with the above code when running in production mode due to the use of class variables and class caching."
I have a test failing and I think it might be due to this but I'm not quite sure what part of the code I shouldn't be using. I had the following (in application.rb):
controller = params[:controller]
action = params[:action]
But I changed that to:
controller = self.class.name
action = params[:action]
How do I access the action name correctly? And in general what kinds of things can you do in development mode that you can't do in production?

Have you considered a role based permissions plugin instead?
See the following stackoverflow question:
Which Rails plug in is best for role based permissions? (Please provide one nomination per answer)
I'm unaware of any issues with production usage of the code you have pasted in. The plugin in question might have some issues due to a possible misuse of ## however, I've not inspected it thoroughly.

Related

no whodunnit in rspec feature test using paper trail

Using Paper Trail, I've built a change tracking element to my app. Works great in production. One aspect is that it uses the 'whodunnit' field to pull the user name to show which user made the change.
I've looked at the documentation (https://github.com/airblade/paper_trail) and I see the notation about rspec and whodunnit, but I didn't think the reference meant the 'whodunnit' field is not available, only that it would be nil'ed between tests.
Details:
I'm using the test helper for rspec, and I have the rspec feature test setup with
"..., versioning: true do"
Moreover, in debugging while running the test, I can see all the other fields for the event/change are there and saved in the database, only whodunnit is not being saved. Interestingly, I'm only having problems in test; no problems in production, works fine there, just doesn't work in test. And of course, I have
before_action :set_paper_trail_whodunnit
set (in my application controller, not the specific controller, but I moved it just to see if it makes a difference, and unsurprisingly, it doesn't).
EDIT:
I should have mentioned that I checked to confirm that there is a column 'whodunnit' in the test database while the tests are running. Also, there is a method current_user (as expected, otherwise it would not work in production) available in the controller.
I found this from a PaperTrail issue on Github
Unless you are running controller and / or integration specs prior to running your query it's likely that the whodunnit column is not being populated.
I ended up manually setting my whodunnit in my specs with
PaperTrail.controller_info[:whodunnit] = user.id
which kind of feels like defeats the purpose a little. But I'm running this in a unit spec vs a feature spec, so I think that's the only way to go.

how find out whether a change is made from UI or from console in rails?

I have a complex Ruby on rails application.
So end users can make changes from th Ui, where as developers can also make changes from the console.
So is there a way to find out whether the change was made from UI or console.
I can capture the end users login details when they make changes from UI but what can I do to know who made changes from the console?
Please help?
The answer is NO, changes from console cannot be traced or tracked. Access to console means access to the whole application with no locks.
When a user has access to rails c he usually has the application in his hands unrestricted. So I am pessimistic in that regard.
You could try to implement/use a restricted console, which implements a current_user method depending on the login on the applications machine. But that might be a bit far fetched for your scenario?
Update: Well...this "roll your own" might be simpler than I thought at first. Of course you can implement an initializer like e.g. current_console_user.rb
module Test3ElementBase
class Application < Rails::Application
config.current_console_user=ENV["USER"] if ENV["RAILS_CONSOLE"] == "Y"
end
end
Then wrap the console call tightly into
RAILS_CONSOLE=Y rails c
Now Test3ElementBase::Application.config.current_console_user is only defined, when called from console. You now "only" have to mix this fact into your original current_user method.
Of course there might be much simpler ways, I'm just a nub :-)

Path security and before_filters rails

I am currently creating an app where users can create and apply for jobs. However as I am fairly new to rails I am facing a fairly significant security feature in that if any user knows the correct path, for example:
localhost:3000/users/user_id/apps
Then they can see any application made by any user for any job!
I am fairly sure that I need to use a before_filter to check that the current_user.id matches either the user_id found in my jobs table for each job or matches the user_id found in my applications table.
I am really not sure how to structure this though or where to apply the filter - for example is it better to create the filter in the application controller and then apply a skip_before_filter instance where needed.
Any help people can offer on contructing this code and where to place it would be much appreciated! Thanks :)
Before you start looking at authorization solutions such as cancan, a simple approach is to avoid doing
App.find params[:id]
Since an app is associated to a user and you've got current_user setup you can do
app = current_user.apps.find params[:id]
Which will only find apps associated with the user, no matter what the parameters to find.
Where cancan really comes into its own is when you need a more complicated who can do what system. For example a user might be able to edit any job they've created but view (and not edit) another set of jobs.
For example
can :manage, Project, :user.id => user.id
can :read, Project, :department => user.department
This would allow users full access to any of their projects and read access to projects in their department
Another thing about cancan is that rather than having before_filters or macros scattered around your controllers you declare the rules in one place, so it's usually easier to see what's going on. There's loads more info on the cancan wiki an a railscast too.
You are right a before_filter might be an sollution but its not the state of the art solution. Theres a railscast for that,...
http://railscasts.com/episodes/192-authorization-with-cancan/
When your using cancan but not devise you need to create the current_user helper that should return the User object of the currently logged in user...

Pitfalls of Thread.local[:current_user]

This question is related to: Access current_user in model.
Specifically, I want to enable access to current_user in one Model.rb. #moif left a comment stating that the solution is not thread-safe, and I have read that there are additional caveats to using this process.
My question is this - if I were to add:
def self.current_user
Thread.local[:current_user]
end
def self.current_user=(usr)
Thread.local[:current_user] = usr
end
to one Model.rb (used only lightly and infrequently), what are the real-world implications for my app and is there anything additional I have to do to ensure its health?
Set up: Rails 1.9, Rails 3.0, Heroku, Authlogic.
I'm not sure I agree about the path you are taking. I agree with the other post that passing the current_user to the model is not appropriate but I wouldn't be using Thread.local for that. Here's why:
Developers love to get technical with solutions and there's not much more "closer to the system" you can get than a Thread.local. Having used Thread.locals before they are very tricky and if you don't get it right then you spend countless hours trying to figure out the problem let alone the solution. It also is difficult to find testers who can understand the complexities of Thread.local and be able to test the code thoroughly. In fact I would wonder how many developers put together solid rspec tests (or equivalent) for something like this. The "cost" of this solution may not be worth it.
I think I would take a look at what you are trying to do and see if there is an easier solution. For example, I can think of two off-hand (maybe would work or not in your case):
a) connect your history table to your user table with a foreign key. "belongs_to, has_many"; or
b) pass the username with attr_accessor on history and set that when creating the object.

Extending a ruby gem in Rails

Let's say I have a Rails app that gets most of it's functionality from a gem (for instance, a CMS).
If I now need to add some customisation (for instance, add a property to a user) what is the best practice way of doing this? If I customise the gem, then I will have issues with updating the gem in the future.
What is the best approach to take here?
This question is quite old, but I feel it could use a bit more fleshing out. It is true that you can monkeypatch rails (and ruby) at run-time. That means it's easy to reopen a class or module and inject new code. However, this is somewhat trickier in rails due to all the dynamic class loading and unloading that goes on development mode.
I won't go into details, but you really want to put your extensions into an initializer, or a gem, since they get reloaded between requests in dev mode. If you put the code into a plugin it won't get reloaded and you'll get very mysterious errors such as "A copy of XXX has been removed from the module tree but is still active!"
The easiest thing to do is throw the code into an initializer (e.g. config/initializers/user_extensions.rb). You can just use class_eval to inject the code.
User.class_eval do
... new code ...
end
One major drawback of ruby's extensibility is tracking down where code is coming from. You might want to add some kind of log message about the extensions being loaded, so people can track it down.
Rails.logger.info "\n~~~ Loading extensions to the User model from #{ __FILE__ }\n"
User.class_eval do
... new code ...
end
Further reading:
http://airbladesoftware.com/notes/monkey-patching-a-gem-in-rails-2-3
Ruby allows you to extend classes in runtime, so you can often hack in to a library without touching the source code. Otherwise I would suggest that you download the gem, create some hooks in the library and submit that back as a patch.
Update:
Note that these customisations are application specific
Yes. What I meant was to modify the generic api in a way, such that it is possible to customise per application. For example, by allowing the user to pass a block to certain methods etc.

Resources