Variable that's accessible to anything in the controller in Rails - ruby-on-rails

I don't know if this is bad form or not, but I needed to set a file path that's accessible to all objects within actions in my controller. One action in the controller creates a file and stores it in a path. Another action serves the file using send_file. The only place I have been storing variables is along with an object in the model. However it seems really silly to store a URL in arbitrarily the first object, or copy the url over all objects. What's the best way to do this?
I hope this was clear.

If this is a file path that is specific to the user of the site, so each user has a different path, you can store it in the session.
session[:file_path] = generate_file!
…user goes to the next page…
send_file session[:file_path]

You could create a method in your application controller that returns the path. This method will then be available throughout your controllers. Don't know if this is necessarily "best practice" but it works for me.

The answer depends on your context. Here is some generic advice:
If there's one file per model, then you need to store one path on each model that has it.
If there's one file shared by several models, but your objects are relatd on a hierarchy, you need to store it on the "father object" - the one that has_many others. The other objects will have to do self.parent.file_path.
Finally, if there's one file used by several non-related models, then I don't know what to suggest, except that maybe there's a better way to organize your models.
What objects are you trying to store, and what relationships are between them?

Related

ZF2 - database and models

I followed this examples http://framework.zend.com/manual/2.2/en/user-guide/database-and-models.html to create a model and a way to save it to a database.
But I don't like the idea of using the AlubumTable-class in my controller as I think this creates too much dependencies. I just want to add the save(), fetchAll(), etc. methods to my model so that I don't have to care about how to save my models inside my controller.
If I want to change the way my models get stored e.g. from a database to a REST-service I would have to rewrite every part of my controller where I get or store models instead of just changing the save() etc. methods in my model.
Are there any tutorials for my way or is this just a stupid idea? :)
The concern you have is actually OK, but you have to realize that the AlbumTable is nothing but a layer between your Controller and the Database. The AlbumTable actually is the one thing with the dependency, not the controller.
The Controller will always need some sort of "Service" or "Gateway" (which would be AlbumTable) to get access to the Data from the DB.
Also i do not understand what you mean by "i want to change the way my models get stored" - You should always store the MODEL into your Service. In the given example the Model is Album and the Service is AlbumTable. No matter where the data comes from - REST, RPC, "normal HTTP", you would always store the Album and not some ArrayData or whatnot. You'd rather try to implement a function inside your model like exchangeArray(), exchangeJson().
You may want to make your "problem" more clear to us...

Reference actual object or just the object Id?

I have this problem of confusing when to include the entire object as a property of another object, or just its ID. It seems that if I include the entire object, the calls to load the containing object will unnecessarily also load the included object when I probably only need references. What is propert approach?
Generally always refer to another object.
Many ORM technologies have the idea of "proxies" and "lazy loading", meaning, unless you reference the object, it won't load it.
I prefer to include the object itself, since one object actually has a relationship with another actual object -- the object ID is just an implementation detail. To deal with the problem of unnecessary calls, look into "lazy loading".
Only include the other object if you need the details.
in MVC use a ViewModel ideally and not your entities. Your ViewModel contains only what it needs, so for example OrderEditViewModel would contain a customerid unless you want to display the custom name, in that case you would include the fields from customer. Some people recomend you flatten out your objects to a view model, so you dont have OrderEditViewModel.Customer.CustomerId but instead ORderEditViewModel.CustomerId. Automapper can help you do this (As well as valueinjecter - note the spelling)
If you must include an ID ensure when you save back to the database your update include a clause to say 'where id=#customerId and (logic here to ensure your user actually has access to that customerid and root object)
I have mvcsecurity.codeplex.com to help encrypt record ids on a web page to prevent against tampering as well (it helps but you should still have something in your query to prevent field tampering so an attacker cant add someone else's customer id for example_)
I go more into parameter tampering in MVC here if anyone is interested:
http://www.pluralsight-training.net/microsoft/Courses/TableOfContents?courseName=hack-proofing-dotnet-app
My suggestion would be to always think about the design and not about performance. Performance can be tweaked but design can't. So, if the two objects have that kind of a relationship where Aggregation/Composition is required, you should do that.
But, if your containing object only has to deal with the ID (for e.g. passing it to a different object which processes the ID to do something) then you can keep the ID field only. No need to expose the whole object (but make sure that your containing object does not need to know anything about the other object.).

In Rails should objects be limited to those that will have a view and controller?

I've been struggling with a design problem, and I admit that I am new to both OOP and RoR so I'm sure this is going to be very basic. I have an application where I am reading from text files in various formats in order to parse information related to hands of poker. So what I have are three entities:
A file object. This stores the name and path of the file and some other attributes, and has functions related to reading from the files. This is MVC because I can add a file and have it be auto-updated, or I can just parse the info from a file on the fly.
The poker hand object. This essentially just stores information about who played the hand of poker and what the actions and results were.
A parser. This reads external JSON files with different regex patterns depending on the type of file that is being read. It also has some basic state machine info in the JSON file so that alot of the logic is removed from the parser.
So my initial feeling about the parser was that it should be its own object. But then I realized that it didn't have a V or a C and so possibly didn't fit with the Rails way of doing things. And it also doesn't have any functionality that is needed by any object other than the file object, and so seemed to fit within the file. But at the same time it's so distinctly different than a file object, that it didn't seem to fit. I thought of a module, but the point of modules seems to be if multiple objects share the need for some functions, and in this case only the file does.
So should it be its own object, be within the file object, or is there some other alternative I'm not seeing?
The decision about whether something should be an "M" in MVC should be based on whether it has any persistent (database-driven) data.
Models don't need a controller or views, and controllers don't have to map one-to-one with models. However, the common "RESTful API" approach does result in a strong model <=> controller correspondence.
In your case it sounds like it's just a chunk of code which takes input and returns some other already-defined model, so it probably sits best as a module in your lib/ folder which you can call from some of your other models or controllers
But then I realized that it didn't have a V or a C and so possibly didn't fit with the Rails way of doing things.
The fact that it doesn't have a V or C is irrelevant in my opinion.
If you feel like the parser belongs with the File, then stick it there. But if you don't (and to me it doesn't sound like it), it's perfectly OK to stick it in it's own class. There is no need that all Models have associated Controllers and Views, nor that they derive from ActiveRecord::Base or any other ORM, nor have anything to do with the database whatsoever.
Regarding whether it belongs in lib or app/models - I look at it like this:
If it's part of your app, it belongs in app/models. If it's not part of your app, like an external library, don't put it in app/models - put it in the lib folder.
It sounds like your parser should be a utility class, rather than part of the model itself. Think of it this way: the model should comprise all of the logic which your application needs to do its job. The parser's job is to get external data into a format which that logic can work on; it's not part of the logic itself.
I'd keep your parser outside File, and put it in lib/.
I use to let classes that implement domain-related logic in the models folder. You should be aware that they won't be automaticly reloaded if let in the /lib folder.

Creating the same model from multiple data sources

This is mostly of a design pattern question. I have one type of model that I'm going to get the data to create them from multiple sources. So for example one record my be created from an API where another is created via screen scraping with Nokogiri.
My issue lies in how best to abstract out these different data sources. Right now I'm building lib classes that return the same hash which I then use to set the attributes of the model. But I'm wondering if this isn't more of a case to use STI. Or if there is some other way of doing this I'm just not thinking about.
I think your design decision would depend largely on what attributes need to be stored. From your description, it sounds like you have a model with multiple data sources, but which would be storing the same attributes regardless of the source. In that case STI seems like overkill. When you retrieve a row from the table, does it matter whether the source is the API or the screen scraper? If not, then you could just define separate methods for each data source and use the appropriate method in the controller.
#instance = MyModel.new(:datasource=>"API")`
I'd say don't worry about inheritance (or mixing in code from modules) unless you really need to. There are some gotchas -- STI is not fully supported by some gems/plugins, for example.

How do I create the Controller for a Single Table Inheritance in Rails?

I am setting up the Single Table Inheritance, using ContactEvent as the Model that ContactEmail, ContactLetter, and ContactCall will all inherit.
But I'm stumped on how to create the routing and the controller.
For example, let's say I want to create a new ContactEvent with type Email.
I would like a way to do the following:
new_contact_event_path(contact, email)
This would take the instance from Contact model and from Email model.
Inside, I would imagine the contact_event_controller would need to know...
#contact_event.type = (params[:email]) # get the type based on what was passed in?
#contact_event.event_id = (params[:email]) #get the id for the correct class, in this case Email.id
Just not sure how this works....
I had similar problem.
See here how I solved it.
I would have a controller (and maybe views) for each of your resource types. So add a controller for ContactEmail one for ContactLetter etc. Don't bother with one for the base class ContactEvent. Then your paths would read something like:
new_contact_email_path(#contact) or new_contact_letter_path(#contact)
The controller actions would then use the right model for that they represent, ie:
#contact_email = ContactEmail.new(params[...])
If you can keep your three types of resources separate rather than trying to pass the type in and building the right object in one controller you should find life much easier. The downside is you may need more links/forms/views in the front end, however depending on your application that may not be a bad thing from the user's perspective.

Resources