How to reference parent model from Carrierwave Uploader object - ruby-on-rails

I want to run some methods after the upload of a file has been completed via Carrierwave. Carrierwave includes several callback methods detailed here.
I'm planning on using the :store callback.
That's great, but it requires me to run the callback method in the Uploader object instance. This isn't the end of the world, but I want to keep all the logic inside of my parent Model.
My question is: How should I be referencing the parent model from the Uploader? I don't see anything obvious in the documentation?
I suppose I could do something like
ParentModel.last.call_my_method_here
but this seems like a very brittle way to code this (not expecting a lot of requests, but still).

I guess the model variable is what you were looking for, see examples using it here

For what it's worth, I have used the after_commit callback on parent model which so far seems to be working properly. This is allowing me to interact with the uploaded file as well.

Related

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

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?

Modifying Rails: How do advanced users find out what needs to be changed?

I've been using Rails for a few months now, and I'm quite comfortable writing up a project & manipulating Rails to my needs, etc.
Recently I've been trying to get a little more advanced, so I've attempted to modify/add to the existing rails codebase: add new form helper methods, add a responds_to :pdf method, etc...and I've been having a lot of problems.
The difficulty is learning which code I need to modify; where that code is located, and how to ensure I don't miss related code in other files. I'm guessing there's a way people learn to do this, but at the moment I'm mostly just guessing-and-hoping.
I guess my question is, how do Rails folks go about learning where the code they need to modify is edited & the approach to editing it? It seems like it's just something you need to know from prior familiarity, but I'm guessing there has to be a simple method for understanding where (and what) to edit.
Any ideas appreciated...cheers
I highly recommend Jose Valim's Crafting Rails Applications
You go through advanced projects, building out the types of engines and customizations that will take you to the next level in your Rails development.
From the site:
This book will help you understand Rails 3’s inner workings, including
generators, template handlers, internationalization, routing, and
responders.
What you are asking for is how MVC works. Basicly you can say:
1.) Put logic to the model! The model is the pivot everything turns around.
2.) The Controller is a middleman between the model and the view. You dont put any logic here that isnt related to selecting data from the database that should be displayed in the view. If you use one selection logic more than once create a scope in the Model and use it in the Controller.
3.) The View is only there to display things! You dont put any logic here! All the logic comes from the model and the data comes from the controller. The only logic your using here are loops through arrays of data that should be displayed.
Then you have some things missing. If you have a task that is related to an external service like lets say a SOAP Service you write a class for that too! Just whithout using ActiveRecord::Base inheritance like its generated by the scaffolder. You can call this Class in other models. Dont put this to the controller or copy the code in every class that needs it! Stay DRY (Dont Repeat Yourself). Just write a class for it and include it in the other models!
Another thing thats a Database basic: Dont store data that could be calculated from other fields from the database! You can add methods that calculate the stuff you need but dont start with duplicates.

should a non-database data class I need be created as a Rails 3 "model", or just a basic class in the /lib area?

should a non-database data class I need be created as a Rails 3 "model", or just a basic class in the /lib area?
I want to build some classes to represent calculated domain objects. So the fields won't reference a database table/column. There will be also methods in the class that with the data.
Question - When generating these classes should these be just normal Ruby classes I put in the /lib area? Or should I/can I use rails models for this (and generate with "rails g model ...")?
Tableless models should probably be kept in app/models. I have several that access APIs. ActiveModel in Rails can help bring in some of the useful functionality of Active Record.
Interesting question..I had the same question a few weeks back.
I put those class under model directory. This is how I came up with that decision. The class that I wrote was completely related to a particular app no common features to share with anyone at-least at the moment. I also needed to use some of my existing models to query some data in that class. So I made it a class under model directory. I might be wrong but thats what I have done now.
In another case where I am using a certain api sets for a web and mobile app I am thinking of making the code which interfaces with the api into a gem. The thing to note here is that the api set is also part my system and it will only be used by my apps.
Classes that don't map to database tables can still reside inside of app/models. Instead of extending your class from ActiveRecord::Base, you can simply declare your class without any extensions (or your own extensions).
The CanCan ability model is a good example of this. It resides in app/models/, however does not extend ActiveRecord::Base. More information on CanCan's ability model can be found here: https://github.com/ryanb/cancan/wiki/Defining-Abilities
Also consider that code under lib/ will not reload in the development environment by default.

Helpers in rails

I'm just starting out in Rails and there's a lot I still need to learn so I'm likely to be on Stackoverflow more often than normal asking beginner Rails / Ruby questions.
I'm just trying to figure out how Helpers work in Rails. From what I've seen so far, Helpers are intended to be used with Views and not so much with your Controllers.
However I would like to make a simple function that will validate the user input given in params (check if certain params are defined and optionally check if their value is valid).
Can anyone explain to me what would be the best way of implementing this? (Keeping in mind that I will want to use this in many different controllers so it should be globally available.)
I also noticed that by default Rails does not generate a lib folder in the main application folder. Are developers to place their libs outside the app folder in the main folder, or does Rails use libraries differently?
With regards to your validation issue, it depends on what you are validating.
If the data makes up objects from your problem domain, also known as models, then you should use the built in validators from ActiveModel. This is probably what you should do, but its hard to say without knowing the exact problem. See the Rails Guides on Validations. You can tell if this is the case by asking yourself if the data that needs validation will be stored after you get it. If so, its most definitely a model. An example of this kind of data would be the title and text fields of a blog post being sent to Rails from a browser form.
If the data is something tertiary to your models, or specific to presentation, then you should be fine using helpers. You noticed that helpers are used mostly in the views, and although this is true, theres nothing stopping you from using them in the controllers, you just have to declare that you will use them using the ActiveController#helper method. Inside the ApplicationController class, a lot of devs will put helper :all to just include all the helpers in all the controllers. Once the code has been required once, it doesn't really incur that big a performance hit.
Do note that almost all incoming data can be modeled using a model. A big school of thought in the Rails world subscribes to the Fat Model idea. People say that putting as much code as possible in the model and as little in the controller as possible separates concerns properly and leads to more maintainable code. This suggests that even if you don't think the incoming data is modelable (in the sense that you can create a model to represent it), you should try to make it a model and encapsulate the logic around validating it. However, you may find that making a helper function is faster, and either will work.
Your notion of validating user input is a good one. I get the feeling that as you are new to Rails you are used to doing these things yourself, but that doesn't quite apply here. In the Rails world, a lot of the common stuff like validations is handled by the framework. You don't have to check for presence in the params array, instead you call validates_presence_of on the model and let Rails spit the error out to the user. It makes things easier in the long run if you let the framework do what it is designed to.
With regards to your question about the lib folder, it doesn't really matter. You can put miscellaneous support files and libraries in the lib folder in the root directory and they will be available for use in your application (the files in the app folder). You can also choose to abstract your code into a plugin or a gem and include it that way, which a lot of people opt to do. My suggestion for this would be to read up on the notion of gems and plugins before diving in.
Want you want is probably a custom validator (in Rails3):
http://railscasts.com/episodes/211-validations-in-rails-3
You can either add libs in a lib folder you create, or add them to config/initializers in a file you add. Files in the initializers directory are automatically loaded by Rails.

Caching ActiveRecord object and associations

I want to be able to "deep clone" 10 instances of an ActiveRecord model and all its associations into memory, work on them, update the in-memory objects and then, when I've finished, pick one to write back over the original in the database.
How do I deep clone (i.e. .clone but also cloning all associations right down to the bottom of the association tree)? I've assumed so far that I'm going to have to write my own method in the Model.
How can ensure that none of the cloned instances will write back to the database until I'm ready to do so?
If possible I'd like to:-
retain all current IDs as one of my main associations is a has_many :through matching the IDs of one model to another
still be able to treat each of the clones as if it were in the database (i.e. .find_by_id etc. will work)
Moon on a stick perhaps? ;)
Not 100% sure of what you are trying to do ...
Models will only be stored in the database if you call the save method. Calling save in an existing model will update the database with any data that has been changed. Associations may be saved also, but it really depends on the type of association and in most cases you will probably need to call save on these models as well.
Doh! Sometimes it takes asking the stupid question before you see the obvious answer.
My issue was that I was having to make changes to the associated objects and they weren't showing up when I used those in-memory objects later so thought I had to save. However, you are right. All that was actually happening was that the variables referencing them had gone out of scope and I was therefore accessing the in-database ones instead.
I'll go back through my code and check that this is the case.
Having said that, it doesn't answer my question on the "deep cloning though" ...
I've solved our deep cloning issues using DefV's deep cloning plugin : http://github.com/DefV/deep_cloning
It's done everything I've required so far, though as you've found you need to be very watchful of your relationships. My tests have luckily shown this up as an issue and I'm working through it at the moment. I found this post as I was trying to solve it :)
Check out the plugin though, it's been quite handy.

Resources