Should i use logger for this or code myself - ruby-on-rails

I am using rails and many of you may find this simple, but i'm confused whether to use logger or just write method calls.
What i'm looking for is that when a user either deletes or updates data using the app, the changes made by the user must to saved to a table in the database with his user name, the record he modified and the time at which he did.
Should i be using
before_delete , before_update
callbacks in model.
I'm really hitting my head, cause i am a beginner in rails. Any suggestion would be most welcome and also please give a insight or links on what i should be doing.

Related

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 :-)

Log user activity gem

i am about to create the functionality for logging user activity in my application. I was thinking of using observers and then log events through another model, something like UserLog.
Before doing that though, i would like to ask if there is already a good gem out there than can save me some time on this.
Do you happen to know any ?
p.s. btw, i am talking about custom defined user activity as well as logging ip addresses and so on. The first case of custom actions logging is more important though.
edit for clarity: I'm not referring to model changes but logging posted form variables and actions like this, not model changes.
audited
audited is an ActiveRecord extension that logs all changes to your models in an audits table, with optional revision comments. acts_as_audited has been updated to work with Rails 3, to use it with older version of Rails .

Create rails form to modify database values - but not with a model

I'm trying to create a universal settings page for my rails app and I have no idea where to start. I know there are several gems that make it simple, and I've read the docs. They enable you to do something like Settings.color = "red" and your settings for color will be red! But, how do I turn this into a form, connected to the database, that the users can then change the values?
Ideally, we need a few settings, I know one of them will be a select box where they have numerous options but only one can be chosen at a time (think Active, Suspended, Disabled, etc).
This isn't really something that a model should be used for because its not a thing, right? I'm totally lost. I can make a database table, but without a model or a controller I have no idea how to just "make a form" that saves into the database - and then how do I get those values out?
Edit: The plug ins I'm referring to are similar to https://github.com/Squeegy/rails-settings and its variants. They show you how to hard code settings which is great, but don't go into how to create a form or any of the back end stuff to make it work. It's not a model so I'm totally clueless here. There's no scaffolding to work off of.
rails-settings is model based, as the readme specifically states that.
So you'd just do as per any other model-based form.

Ruby on Rails: how to use sessions to implement remote sign-out?

My goal is to allow users of a Rails web app to see all their open sessions on other computers and close/sign out of them remotely. Similar to gmail's "Account activity" page (link found at the bottom of the gmail inbox page).
I can technically achieve this by using the sessions in the database
account_sessions = CGI::Session::ActiveRecordStore::Session.find(:all)
and iterating over them to find sessions corresponding to the current user (the user ID is stored in the session data), and allowing the user to destroy these sessions.
However, this doesn't offer the usual convenience of working with Rails models. I can't easily express a has_many relationship with the user and make use of
current_user.sessions
nor can I easily put an index on user_id since it's in the data part of the session (instead of being its own column).
This approach also may become impractical if the number of sessions grows, since in the above the table is read into memory.
As a solution, I'm thinking of creating my own model which "mirrors" the relevant portions of the session and is created/updated/destroyed to maintain that correspondence.
This isn't a great way to go about it due to data replication and added complexity of code, but I didn't find another way to do it.
So the question is: is this a good way to go about it, or am I missing something?
Thanks in advance!
Fraser
Edit: I should have mentioned that I'm currently using restful-authentication, and would prefer not to switch.
Since authlogic offers a user session model and is easily extendable, you should be able to achieve exactly what you want, if you don't mind to switch to another authentication mechanism.
Edit: This Railscast should give you a pretty good overview.

ActionMailer best practices: Call method in the model or the controller?

Sending an email is usually called after an action on a model, but the email itself is a view operation. I'm looking for how you think about what question(s) to ask yourself to determine where to put the action mailer method call.
I've seen/used them:
In a model method - bad coupling of related but seperate concerns?
In a callback in the model (such as after_save) - best separation as far as I can tell with my current level of knowledge.
In the controller action - just feels wrong, but are there situations were this would be the smartest way to structure the code?
If I want to know how to program I need to think like a programmer, so learning how you go about thinking through particular programming solutions is worth months of coding on my own in isolation. Thank you!
Late answer, but I want to rationalize on the subject:
Usually, in a web app, you want to send emails either as a direct reaction to a client. Or as a background task, in case we're talking about a newsletter/notification mail sort of thing.
The model is basically a data storage mapper. Its logic should encapsulate data-handling/communication with data storage handling. Therefore, inserting logic which does not relate to it is a bit tricky, and in most cases wrong. Let us take the example: User registers an account and should receive a confirmation email. In this case one could say, the confirmation email is a direct effect of the creation of a new account. Now, instead of doing it in the web app, try to create a user in the console. Sounds wrong to trigger a callback in that case, right? So, callback option scratched. Should we still write the method in the model? Well, if it's a direct effect of a user action/input, then it should stay in that workflow. I would write it in the controller after the user was successfully created. Directly. Replicating this logic in the model to be called in the controller anyways adds unnecessary modularity, and dependency of an Active Record model from Action Mailer. Try to consider sharing the model over many apps, in which some of them don't want Action Mailer for it. For the stated reasons, I'm of the opinion that the mailer calls should be where they make sense, and usually the model is not that place. Try to give me examples where it does make.
Well, depends.
I've used all of those options and your point about 'why should I put this where?' is good.
If it's something I want to happen every time a model is updated in a certain way, then I put it in the model. Maybe even in a callback in the model.
Sometimes you're just firing off a report; there's no updating of anything. In that case, I've normally got a resource with an index action that sends the report.
If the mailer isn't really related to the model that's being changed, I could see putting it in a callback. I don't do that very often. I'd be more likely to still encapsulate it in the model. I've done it, just not very often.
I'm aware it's been a while but best practices never die, right? :)
Email is by definition asynchronous communication (except for confirmation email, but even this one it should be a best practice to leave a delay before having to confirm).
Hence in my opinion, the most logical way to send it is :
in a background action (using Sidekiq or delayed_job)
in a callback method : "hey this action is successfully done, maybe we can tell the world now?"
Problem in Rails is that it is not too many callbacks (as in JS for instance): I personnaly find it dirty to have code like:
after_save :callback
def callback
if test_that_is_true_once_in_the_objects_life
Mailer.send_email()
end
end
So, if you really want to think like a programmer, the idea would be to set up some custom callback system in your app.
Eg.
def run_with_callback(action, callback_name)
if send(action)
delay.send(callback_name)
end
end
Or even creating an event system in your app would be a decent solution.
But in the end those solutions are pretty expensive in time so people end-up writing it inline after the action
def activate
[...]
user.save
Mailer.send_mail
respond_to
[...]
end
which is the closest fashion to callback in synchronous programming and results having Mailers call everywhere (in Model and in Controller).
There's several reasons why controllers are a good place for the mailers:
Emails that have nothing to do with a model.
If your emails depend on several models that dont know about each other.
Extracting models to an API should not mean reimplementing mailers.
Mailer content determined by request variables that you dont want to pass to the model.
If your business model requires a lot of diferent emails, model callbacks can stack.
If the email does not depend on the result of model computations.

Resources