A model with a handful of id's - ruby-on-rails

I have a model which has many of another model but this model only needs to have 10 or less id's in it.
Let's say it has, Bathroom, Kitchen, LivingRoom for arguments sake and the new records will probably never need to change.
What is the best way of making a model like this that doesn't use a database table?

This may not be best practices, but to solve the same problem I just specified a collection in my model, like this:
ROOM_TYPES = [ "Bathroom", "Living Room", "Kitchen" ]
Then in the view:
<%= f.select(:room_type, Project::ROOM_TYPES, {:prompt => '...'}) %>
(replace Project with your actual model name.)
Super-straightforward, almost no setup. I can see how it would be difficult to maintain though, since there's no way to add items without accessing the Rails code, but it does get the job done quickly.

Even though the collection of rows never changes, it's still useful to have this as a table in your database in order to leverage ActiveRecord relations. A less contrived example would be a database table that has a list of US states. This is highly unlikely to change, and would likely have only a couple of columns (state name and state abbreviation). However, by storing these in the database and supporting them with ActiveRecord, you preserve the ability to do handy things like searching for all users in a state using conventional rails semantics.
That being said, an alternative would be to simply create a class that you stick in your models directory that does not inherit from ActiveRecord, and then either populate it once from the database when the application loads, or simply populate it by hand.
A similar question was asked yesterday, and one of the answers proposes a mechanism for supporting something similar to what you want to do:
How to create a static class that represents what is in the database?

Related

ActiveRecord schema for multiple types of objects with common columns?

I'm working on a Rails 5 app for Guild Wars 2, and I'm trying to figure out a way to serialize and store all of the items in the game without duplicating code or table columns. The game has a public API to get the items from, documented
here: https://wiki.guildwars2.com/wiki/API:2/items
As you can see, all of the items share several pieces of data like ID, value, rarity, etc. but then also branch off into specific details based on their type.
I've been searching around for a solution, and I've found a few answers, but none that work for this specific situation.
Single Table Inheritance: There's way too much variance between items. STI would likely end up with a table over 100 columns wide, with most of them null.
Polymorphic Associations: Really doesn't seem to be the proper way to use these. I'm not trying to create a type of model that gets included multiple other places, I just want to extend the data of my "Item" model.
Multiple Table Inheritance: This looks to me like the perfect solution. It would do exactly what I'm wanting. Unfortunately, ActiveRecord does not support this, and all of the "workarounds" I've found seem hacky and weird.
Basically, what I'm wanting is a single "Item" model with the common columns, then a "details" attribute that will fetch the type-specific data from the relevant table.
What's the best way to create this schema?
One possible solution:
Use #serialize on the details (text) column
class Item
serialize :details, Hash
end
One huge downside is that this is very inefficient if you need to query on the details data. This essentially bypasses the native abstractions of the database.
I was in a similar situation recently. I solved by using Sequel instead of ActiveRecords.
You can find it here:
https://github.com/TalentBox/sequel-rails
And an implmentation example:
http://www.matchingnotes.com/class-table-inheritance-in-rails.html
Good luck

Ruby on Rails - Alternatives to STI?

I have many different models (close to 20) that share some common attributes but also differ to some degree in others. STI seems attractive at first, but I have no idea how the various models will evolve over time with rapid product development.
A good parallel to our application that comes to mind is Yelp. How would Yelp manage something in Rails? All of the postings have some common attributes like "address". Yet, they differ quite a lot on others. For example, you have a reservation option for restaurants and maybe not for others. Restaurants also have a ton of other attributes like "Alcohol allowed" that don't apply to others. Doing this with STI will get out of hand pretty quickly.
So whats the next best option? HStore with Postgres? I am not comfortable using HStore for anything but small things. HStore solves some problems while introduces others like lack of data types, lack of referential integrity checks etc. I'd like a solid relational database as the foundation to build upon. So in the Yelp case, probably, a restaurant model is where I am going. I've taken a look at suggestions like here - http://mediumexposure.com/multiple-table-inheritance-active-record/, but I am not happy to do so much monkey patching to get something so common going.
So I am wondering what other alternatives exist (if any) or should I just bite the bullet, grind my teeth and copy those common attributes into the 20 models? I am thinking my problems would come from the migration files rather than the code itself. For example, if I setup my migrations to loop through tables and set those attributes on the tables, then would I have mitigated the extent of the problem with having different models?
Am I overlooking something critical that might cause a ton of problems down the road with a separate models?
I see a few options here:
Bite the bullet and create your 20 different models with a lot of the same attributes. It's possible that these models will drift over time - adding new fields to one specific type - and you'll create a 200 column table with STI. Maybe you don't - the future is hard to see, especially with exploratory/agile software.
Store non referential fields in a NoSQL (document) database. Use your relational database for parts of the record that are relational (a user has many reviews and a review has one business), but keep the type specific stuff in a NoSQL database. Keep an external_document_id in your Rails models and external_record_id / external_record_type in your NoSQL document schema so you can still query all bars that allow smoking using whatever NoSQL ORM you end up using.
Create an Attributes model. An attribute belongs_to :parent_object, polymorphic: true with a key and value field. With this approach you might have a base Business model and each business can has_many :attributes. Certain (non-relational?) attributes of the business (allows_smoking) are one Attribute record. An Attribute's key could be a string or could be a numeral you have Ruby constants for. You're essentially using the Attribute entities to create a SQL version of option #2. It might be a good option, and I've used this myself for User or Profile models. (Although there are some performance hits to be aware of with this approach).
I'd really worry about having that many (independent) models for something that sounds subclass-ey. It's possible you might be able to DRY up common behavior/methods by using Concerns (syntactic sugar over the mixin concept, see an awesome SO answer on concerns in Rails 4). You still have your (initial) migration problem, of course.
Adding another option here: Serialized LOB (272). ActiveRecord allows you to do this to an object using serialize:
class User < ActiveRecord::Base
serialize :preferences
end
user = User.create(preferences: { "background" => "black", "display" => large })
User.find(user.id).preferences # => { "background" => "black", "display" => large }
(Example code from ActiveRecord::Base docs.)
The important consequence to understand is that attributes stored in a Serialized LOB will not be indexable and certainly not searchable in any performant manner. If you later discover that a column needs to be available as an index you'll have to write [most likely] a Ruby program to perform the transformation (though by default serialization is in Yaml so any Yaml parser will suffice).
The advantage is that you don't have to make any technology changes to your stack in order to apply this pattern. Its easy to moderate - based on the amount of data you have collected - to migrate away from this pattern.

Rails: associations in app with one model

I've read so many Rails books/tutorials, but when it comes time to actually make the app, I keep tripping over myself, so I'm trying this little exercise to help me get it better.
I have an app with 3 classes (Link, Url, Visit) that have associations defined between them, such as has_one, belongs_to etc. This allows me to call methods like Link.url
If I were to convert this into an app with a single model, is it possible to create the convenience methods (such as Link.url) even though there are no relationships between models, because there is only one model.
This might not be the 'Rails way' but if you answer this question it'll help me get it more.
I guess another way to ask this is, do the Rails associations only exist because the tab
Thanks
Models exist to represent tables in a database. If you have 3 different conceptual objects, then you need 3 different models. Keeping those objects separate and in different tables/models is essential to good programming in any language. The relations are there to help you understand the correlation of each object to the others.
If you think all of data from each of the models can be represented in one table sensibly, then combine them in to one model with a name that encompasses all of the data. If you choose this option, you'll use columns for that one table which represent each of the pieces of data you need. Those column names come free in the model when you create the migration. A table with a column named "url" on a model named "Hit" could be used like this:
Hit.first.url

Dynamically creating new Active Record models and database tables

I am not sure exactly what I should name this question. I just started server-side programming and I need some help.
All the tutorials I have read so far on RoR deal with creating a pre-defined table and with pre-defined fields (id, name, email, etc etc). They use ActiveRecord as base class and saving to db is handled automatically by superclass.
What I am trying to program is something that allows user-defined table with fields. So think of this way. The web UI will have an empty table, the user will name the table, and add columns (field), and after that, add rows, and then later save it. How would I implement this? I am not asking for details, just an overview of it. As I said, all the tutorials I have read so far deal with pre-defined tables with fields where the ActiveRecord subclass is predefined.
So in a nutshell, I am asking, how to create tables in db on runtime, and add fields to the tables.
Hope I was clear, if not, please let me know and i will try to elaborate a bit more.
Thanks.
Unless you're building a DB administration tool (and even maybe then), allowing the user direct access to the database layer in the way you're suggesting is probably a bad idea. Apart from issues of stability and security, it'll get really slow if your users are creating lots of tables.
For instance, if you wanted to search for a certain value across 100 of your users' tables, you'd have to run 100 separate queries. The site would get exponentially slower the more user tables that were created.
A saner way to do it might be to have a Table model like this
class Table < ActiveRecord::Base
has_many :fields
has_many :rows
end
Every table would have fields attached to it, and rows to store the corresponding data (which would be encoded somehow).
However, as #Aditya rightly points out, this is not really beginner stuff!
I agree with previous answers generally speaking. It's not clear from your question why you want to create a table at runtime. It's not really obvious what the advantage of doing this would be. If you are just trying to store data that seems to fit into a table with rows and columns, why not just store it as an array in a field of your user table. If your user is allowed to create many tables, then you could have something like
class User < ActiveRecord::Base
has_many :tables
end
and then each table might have a field to store a serialized array. Or you could go with Alex's suggestion - the best choice really depends on what you are going to do with the data, how often it changes, whether you need to search it and so on ...
You can create a database as shown in tutorials which stores name of tables and their columns name those your user want. Then you can have worker (which can be build using Redis and Resque, here is simple Tut on Resque and Redis) and have those worker run migration (write migration with variables and use params to replace them) for you for new table in DB as soon as new entry is made in database. Tell me if you have questions on this.

Rails 3.0 - best practices: multiple subtypes of a model object

So this is probably a fairly easy question to answer but here goes anyway.
I want to have this view, say media_objects/ that shows a list of media objects. Easy enough, right? However, I want the list of media objects to be a collection of things that are subtypes of MediaObject, CDMediaObject, DVDMediaObject, for example. Each of these subtypes needs to be represented with a db table for specific set of metadata that is not entirely common across the subtypes.
My first pass at this was to create a model for each of the subtypes, alter the MediaObject to be smart enough to join into those tables on it's conceptual 'all' behavior. This seems straightforward enough but I end up doing a lot of little things that feel not so rails-O-rific so I wanted to ask for advice here.
I don't have any concrete code for this example yet, obviously, but if you have questions I'll gladly edit this question to provide that information...
thanks!
Creating a model for each sub-type is the way to go, but what you're talking about is multiple-table inheritance. Rails assumes single-table inheritance and provides really easy support for setting it up. Add a type column to your media_objects table, and add all the columns for each of the specific types of MediaObject to the table. Then make each of your models a sub-class of MediaObject:
class MediaObject < ActiveRecord::Base
end
class CDMediaObject < MediaObject
end
Rails will handle pulling the records out and instantiating the correct subclass, so that when you MediaObject.find(:all) the results will contain a mixture of instances of the various subclasses of MediaObject.
Note this doesn't meet your requirement:
Each of these subtypes needs to be represented with a db table for specific set of metadata that is not entirely common across the subtypes.
Rails is all about convention-over-configuration, and it will make your life very easy if you write your application to it's strengths rather than expecting Rails to adapt to your requirements. Yes, STI will waste space leaving some columns unpopulated for every record. Should you care? Probably not; database storage is cheap, and extra columns won't affect lookup performance if your important columns have indexes on them.
That said, you can setup something very close to multiple-table inheritance, but you probably shouldn't.
I know this question is pretty old but just putting down my thoughts, if somebody lands up here.
In case the DB is postgres, I would suggest use STI along hstore column for storing attributes not common across different objects. This will avoid wasting space in DB yet the attributes can be accessed for different operations.
I would say, it depends on your data: For example, if the differences between the specific media objects do not have to be searchable, you could use a single db table with a TEXT column, say "additional_attributes". With rails, you could then serialize arbitrary data into that column.
If you can't go with that, you could have a general table "media_objects" which "has one :dataset". Within the dataset, you could then store the specifics between CDMediaObject, DVDMediaObject, etc.
A completely different approach would be to go with MongoDB (instead of MySQL) which is a document store. Each document can have a completely different form. The entire document tree is also searchable.

Resources