I have a model of say Apps and each App contains a bunch of users, and a reference to the store type, and has the properties, name, app_id, version, and price.
I want to be able to create clones of this app, which has all the same values, save for version, and store type.
I'd like to do this by adding a property/column to my app called "Is_clone", and I'd like a second table called AppToClone, which has two columns App and Clone.
In each row, I'll have say App:1 , Clone:[2,5,7,26]
This way I can edit each clone as its own app, but at the same time I can apply any changes in an app to all its clones.
I've set up the database for AppToClone but I'm stuck on how to create this association within the App Model itself. Examples I've found so far such as the gem rails_lookup_tables seems to only allow a single value rather than an array in the AppToClone table.
Currently in my App model I have the following line:
:has_many :apps, through: :appstoclones
But this doesn't feel correct to me, and I'm not sure how to build that database over time.
Feeling kinda stupid here, but I'm stuck.
So the has_many and belongs_to association stores the data in a different way than the question indicates. I would use single table inheritance, having a Clone model inherit from the App model.
class App < ActiveRecord::Base
has_many :clones
end
class Clone < App
belongs_to :app
end
You would need to have an app_id and type on your app table (strange I know), so your clone can be associated. What you would be able to do then is query your clone as an App.
Clone.last.is_a? App
-> true
What I think is closest to what you actually want though, is outlined in section 2.10 Self Joins of the Ruby on Rails Guides.
class App < ActiveRecord::Base
has_many :clones, class_name: "App",
foreign_key: "parent_app_id"
belongs_to :parent_app, class_name: "App"
end
You need to create the foreign_key in a migration.
To implement the is_clone:
def is_clone?
!!self.parent_app_id
end
To implement the AppToClone:
def clone_ids
self.clones.all.map(&id)
end
# Check it in the console:
App.last.clone_ids
-> [2,5,7,26]
The biggest concern here is thinking that a table will have a row with one column holding an array. That is not normalized! Normal associations work by having the foreign keys as seen in these examples, one per row. If you have a complex has_and_belongs_to_many relationship, the table that holds keys has two columns, each with one id.
Per the request in the comment below (self join update):
def clone_me
self.clones << self.clone
end
> new_cloned_app = App.last.clone_me
The reference for using has_many is found: In the rails guide here. Feel free to use a different helper function. Also, the returned value must be .saveed
I would say you are looking for a has-many belongs-to relationship.
For the has-many part: http://guides.rubyonrails.org/association_basics.html#the-has-many-association
For the belongs-to part: http://guides.rubyonrails.org/association_basics.html#the-belongs-to-association
One model would be the app, the other clone, where the clone table would store the the same fields an app has, as well as the additional fields needed for a clone instance. By inheriting the clone model from the app model which inherits from ActiveRecord, one can use a clone in the code where an app is used.
Related
I currently have a few models, users, clients, addresses and contacts.
I used scaffold to create my client model which only contains name, leadsource and DBA. It is currently working just fine.
My address and contact was created separately as a client can have many addresses and contacts and they require a client_id to set up the relationship.
Assuming I am using your standard crud operations, is there any way to set up a single nested form that will allow me to add all 3 at once?
Sure, the standard way is fields_for.
But normally you also want to dynamically add and remove associated objects (i.e. addresses) and that's a bit more advanced.
There are gems to help you. i.e. cocoon and a great railscast: episode 403.
Unfortunately it's a pro episode, but investing the $9 is well worth it, as the railscasts really are a source of inspiration (at least for me).
I assume, you already have the associations or create them:
rails generate migration AddClientReferenceToAddress client:references
rake db:migrate
and in models:
class Client < ActiveRecord::Base
has_many :addresses
end
class Address < ActiveRecord::Base
belongs_to :client
end
Ive finished Learning Rails 3 by O'Really, and now its time to experiment knowledge on a real project and I'll be deploying to Red Hat's OpenShift platform.
Searching trough my laptop code projects folder, I came out with a simple TODO task manager ive wrote once in C++. So it would be a good idea to bring that project back to life, this time as a web task managing service in Rails, allowing auth with OmniAuth.
The original C++ project was planned on a OOP point of view. You could create a "Task" object with its current ID number, Text string, Date ,and Time.
Every part of a task was made as a different C++ class. Eash one cointains its validation on the constructor.
And then saved the tasks to sqlite or exporting them as a plain text that you could share or read again on the app.
So, back to business, I'm trying to adapt that little app into something more complex in Rails using MVC.
I thought about adding a Scaffolding that brings the form to fill the task's text field and pass it to the Controller.
The controller will set current date and time, and ID is set by default when saving to the DB.
Validations should go on the model, and I'll create a migration to build a table upon that fields.
As I'll be adding multiuser support with OmniAuth, (so every user could save his own tasks), I should create a new DB table, with users info.
But should I create a new task table for each user, and then mapping them to the users table?
Or just create one task table and drop every user's tasks in there and then mapping all there?
I cant figure out a good with saving user tasks to the db.
Any ideas?
Thanks in advance
This is assuming that a User can have many tasks, but a Task can belong to only one user.
You'll have one tasks table and put all user's tasks there.
You'll want to add a user_id column to the tasks table (rails g migration add_user_id_to_tasks user_id:integer) and add the following to the models -
class Task < ActiveRecord::Base
belongs_to :user
end
class User < ActiveRecord::Base
has_many :tasks
end
Reference: Rails Guide to ActiveRecord Associations
You models will look like this:
class User < ActiveRecord::Base
has_many :tasks
end
class Task < ActiveRecord::Base
belongs_to :user
end
Your tables will look like this (in pseudo-ad-hoc-notation):
Users table => id:integer, name:String
Tasks table => id:integer, task:Text, user_id:integer
Does this help?
Here is my situation. I have model called Account. An account can have one or more contracts. The problem is that i'm dealing with a legacy application and each account's contracts are stored in a different database.
Example:
Account 1's contract are in account1_db.contracts.
Account 2's contract are in account2_db.contracts.
The database name is a field stored in accounts table.
How can i make rails association work with this?
This is a legacy PHP application and i simply can't change it to store everything in one table. I need to make it work somehow.
I tried this, but it didn't worked:
has_many :contracts, :conditions => [lambda{ Contract.set_table_name(self.database + '.contracts'); return '1' }]
Any ideas?
Why isn't database migration an option?
You're approaching this the wrong way. You want the two systems in your integration to be loosely coupled. By trying to get the two associated, you're creating an array of interdependencies that will later come around to backstab you. The approach you are trying creates tight coupling and reduces cohesion.
But, to directly answer your question, see below. Once again, I don't recommend implementing what I say below, but it would technically be a solution.
The first thing is that rails associations work only with foreign key. In fact, all database associations work this way. There isn't a ActiveRecord method of association without foreign keys as it defies what it means to associate two objects.
So you're not going to get it done with a has_many association. Instead, I would just manually create a function on your Contract model that simulates a has_many association.
class Account
memoize :contracts
def contracts
# Load from other database in here
end
def contracts=
# Push to other database in here
end
end
I'm porting some functionality to Rails, and I'm working with an existing table which is for comments.
Basically, there are two types of comments - profile comments (photo_id column is null) and photo comments (photo_id column is set to photo's ID)
I got single table inheritance working just fine by adding a type field to the table, but I'm wondering if there's a way to get my single table inheritance working without the type field. According to the Rails API documentation, "If you don‘t have a type column defined in your table, single-table inheritance won‘t be triggered. In that case, it‘ll work just like normal subclasses with no special magic for differentiating between them or reloading the right type with find."
I'm wondering if there's a way that I can customize my models to determine type based on photo_id being nil or having an integer value, rather than using the database column (which I'd rather not add if I don't have to.) Any ideas?
If comments models doesn't differ much, I wouldn't bother with single table inheritance at all. Just add:
# to Comment model
belongs_to :photo
belongs_to :profile
# to Profile model
has_many :comments
# to Photo model
has_many :comments
Then:
#photo.comments # will return comments associated with photos
#profile.comments # will return comments associated with profiles
There may be problem if you had both photo_id and profile_id set (I suppose it may happen when you comment a photo that is associated with profile), so you can change in Profile model:
has_many :comments, :conditions => "photo_id is not null"
Another approach (I think better) it to you polymorphic associations but you will need to modify you sql tables.
I suspect you cannot do this trivially. However, one possibility is to trick active record into using a view rather than a table, and write some database functions to set this magic attribute based on which id is set.
However, in the end, I suspect it would be far, far easier to just add the column.
So I'm working on a Rails app to get the feeling for the whole thing. I've got a Product model that's a standard ActiveRecord model. However, I also want to get some additional product info from Amazon ECS. So my complete model gets some of its info from the database and some from the web service. My question is, should I:
Make two models a Product and a ProductAWS, and then tie them together at the controller level.
Have the Product ActiveRecord model contain a ProductAWS object that does all the AWS stuff?
Just add all the AWS functionality to my Product model.
???
As with most things: it depends. Each of your ideas have merit. If it were me, I'd start out this way:
class Product < ActiveRecord::Base
has_one :aws_item
end
class AWSItem
belongs_to :product
end
The key questions you want to ask yourself are:
Are you only going to be offering AWS ECS items, or will you have other products? If you'll have products that have nothing to do with Amazon, don't care about ASIN, etc, then a has_one could be the way to go. Or, even better, a polymorphic relationship to a :vendable interface so you can later plug in different extension types.
Is it just behavior that is different, or is the data going to be largely different too? Because you might want to consider:
class Product < ActiveRecord::Base
end
class AWSItem < Product
def do_amazon_stuff
...
end
end
How do you want the system to perform when Amazon ECS isn't available? Should it throw exceptions? Or should you rely on a local cached version of the catalog?
class Product < ActiveRecord::Base
end
class ItemFetcher < BackgrounDRb::Rails
def do_work
# .... Make a cached copy of your ECS catalog here.
# Copy the Amazon stuff into your local model
end
end
Walk through these questions slowly and the answer will become clearer. If it doesn't, start prototyping it out. Good luck!
You can use the composed_of relationship in ActiveRecord. You make a regular class with all the attributes that you manage through AWS and specify that your Product-class is composed_of this class. ActiveRecord will handle the delegation of the mapped attributes to and from this class.
See the documentation of composed_of
#Menno
What about using ActiveResource for the AWS-attributes class?
If you are retrieving data from two completely different sources (ActiveRecord on one hand and the Internet on the other), there are many benefits to keeping these as separate models. As the above poster wrote, Product has_one (or has_many) :aws_item.