Rails - Best way to have an api call whenever object is updated - ruby-on-rails

What is the best way to have an api called whenever an object is updated?
Placing the call inside the model with after_update doesn't seem very clean, and in some cases it may be necessary to have the current_user from devise. Also calling the api everywhere that the object is changed (we have a few ways to save a sale, for instance) doesn't sound very clear either
What is a good way to do this?

Related

Should i use logger for this or code myself

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.

rails mvc helper class for calling outside data (Viddler)

I've got an app that is using Viddler's API and the viddler-ruby gem. Originally there was only one spot in the app that was going to authenticate and request video information, but there's been a change and I might need to do it in a few places.
I could do it as a method in application_helper but then whenever that method would be called it would authenticate and perform a function (and as I'm thinking about it, there could be more than one function needed).
So I'm thinking a class upon instantiation, authenticates, keeps that authenticated #viddler object and has public methods that can be called on the class (ie ViddlerMaster.getImage(video)) -- my question is is this a controller or a model? In my thinking it's dealing with data so it'll be a model, one that doesn't connect to the database in any way; is my thinking correct, or is there A Better Way?

current_user available in an observer

OK, so I know this has been brought up before, and I realise that this breaks the MVC model in a purists view. However, I really think that things such as current_user or current_tenant should be available in an observer.
My specific case is that after actions have been done on a subset of my models (about half a dozen) I want something to be written to an audit log that includes the user that made the change and the tenant that made that change as well.
The first way to do this is to add a line to each controller method that carries out that function. To make this DRYer the actual activity is carried out in the application controller or the auditlog model and a simple one line statement is called from the controller. However this still means adding in the line, which isn't great and would be a whole lot more elegant if it were done in an observer.
However since an observer has no way of knowing what current_user is, this isn't possible. I've seen some work around using Thread, but these do not look that safe to me.
Now if anyone does have a more elegant solution, I'd love to hear it. Otherwise this is my case that we should have access to some controller methods in an observer. I'd like to get a sense of the feeling out there before putting this to the rails core dev team.

Rails: elegant way to get user_agent in a before/after callback?

I have an :after_update callback that records edits to one of my models.
I'm wondering if there is an elegant way to get the user_agent into in this callback when the edit came from a web request.
I know it's in the model, which doesn't have access to the request object. And it doesn't have to be edited from a web request. For example, if edited from the console, it would be fine if user_agent were nil in that case.
The only alternative I can think of is to find every controller action which might update the model and make the call from there, but this is a huge code base that is changing rapidly so it would be easy to miss something this way.
Maybe there is a clever way to put an attr_acessor on the model called user_agent (not stored in database) and ensure every controller action populates this on an edit? But not sure.
Thanks!
Elegant I'm not sure about, but I believe Rails will use 1 thread per request (spawns it off to process it), so you can do
Thread.current[:my_user_agent] = request.user_agent
and that is accessible all the way through the app for the duration of that request. I'm also fairly sure that's not documented behaviour, so you might have issues if Rails modifies it.

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