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?
Related
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?
I'm developing a plugin for Redmine (RoR 4.2) that should send data to a different system once an Issue of a certain type is created/updated.
I've created a patch for Issue containing two callbacks: before_update and after_create. Both call the same method to execute. The reason why I use after_create is that I need to send the ID of a newly created Issue to the second system.
My problem here is that while returning false from before_update cancels the transaction, doing so from after_create has no effect. To handle this I need to throw an Exception which in its turn breaks the Issue controller making it return Error 500 page instead of a nice error popup.
So what is the best way to handle this situation taking into account that I'm not willing to override the controller (if possible)?
This sounds like a fool's errand since exceptions are generally handled on the controller layer. Of course you can rescue the exception in your callback method and for example log a message.
But you can't really effect the controllers outcome from a model callback without resorting to some really nasty hacks. The model should only be concerned with its own state - not the application flow.
And ActiveRecord does not really care about the return value from after_* callbacks.
Fat models and skinny controllers are good. But letting your models do stuff like talk across the wire or send emails is usually a horrible idea. ActiveRecord models are already doing a million things too many just maintaining your data and business logic. They should not be concerned with stuff like what happens when your request to API x fails.
You might want to consider using a Service Object to wrap creating and updating the model instead.
I wonder if there is any doc on that. I believe it is helpful to know when those objects get created and destroyed and whether they are re-used (like Java servlets). Particularly, I am wondering about helpers. I assume a new controller instance is created for every new request, and the same is true for views but not for helpers. In his tutorial Michael Hartl uses SessionsHelper to store the current user, which makes me think helper lifetime is bound to the session. Is this correct? Then technically I can use helpers to store session info, right?
The basic flow goes like this:
(request) -- Rack stuff -- Controller instance -- View instance -- (response)
Any instance variables you set in the Controller are made available to the View. Those are threadsafe. Class variables, on the other hand, are not threadsafe.
Helpers are Modules, not Classes, so they aren't (can't be, really) instantiated. Instead, they're mixed into the View instance that evaluates your templates. Again, instance variables are threadsafe, class variables aren't.
My thinking is that helper methods, as with every other part of a Rails app, is created & destroyed with each request
You have to remember the helper methods will not "store" any session data - they'll only call the session cookies to display the relevant data:
Most applications need to keep track of certain state of a particular
user. This could be the contents of a shopping basket or the user id
of the currently logged in user. Without the idea of sessions, the
user would have to identify, and probably authenticate, on every
request. Rails will create a new session automatically if a new user
accesses the application. It will load an existing session if the user
has already used the application.
A session usually consists of a hash of values and a session id,
usually a 32-character string, to identify the hash. Every cookie sent
to the client's browser includes the session id. And the other way
round: the browser will send it to the server on every request from
the client. In Rails you can save and retrieve values using the
session method:
This demonstrates, to me at least, that every time you load a "helper", it's really relying on the user's stored data (particularly for the session). This means that although it may appear that a helper's lifecycle may extend beyond each request, it's really just relying on the data provided
Having said that, I need to read up on how to make this threadsafe etc, as per benjamin sinclaire's comment
I am building a sample app for learning rails 4, and I'm a little confused on where I'm meant to build certain things. For example, I want to check if a user is logged in, and if so, display their account balance in the header (a partial).
Thanks to Michael Hartl's tutorial, I have a function to check a user's login status in the session helper, which is included in the application controller and can therefore be accessed in the partial.
Since the balance is tracked in the Users table, do I build a function get_balance in the Users model? Or should I create a function in the application helper? If I do build it in the application helper, is this auto-included in the application controller, or do I have to include it specifically? If I don't build the function in the model, can I still access the User object?
Thanks for your patience with a noob.
Since your users balance is a column in Users table, it is already there for you as a field (most possibly user.balance). And yes, this is where you should store it. You might use helpers for stuff that is related to general layout of your application and use combination of partial view and layout to spread it around.
Since it's already on your table, assuming your user is logged in, you could just call
current_user.balance
But it sounds like you want to add onto the data given,
I would suggest perhaps using a Rails decorator for your user model.
Basically a decorator adds an object-oriented layer of presentation logic to your Rails application.
I use the Draper Gem
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.