I need to specify a field name different than the table for association - ruby-on-rails-3

Given I have an Artifact model and a User model: I would like to define two Artifact fields, opened_by and assigned_to, who values are User ids and inherit all of the proper association methods.
What is the proper belongs_to or has_one or has_many options I should set?
The goal is to be able to reference the user's name through the statement hld.assiged_to.name where hld is an artifact.
Thanks for the help. I've gotten myself confused with terminology with all of the reading i've done on the problem.

The following is what I determined was correct.
class Artifact < ActiveRecord::Base
belongs_to :project
belongs_to :opened_by, :class_name => 'User'
belongs_to :assigned_to, :class_name
=> 'User'
The first argument in the belongs_to specifies the field to reference. The second indicates the model/class to use as the reference.

Related

How can I introduce a has_one_belongs_to_one association in Rails model?

My Rails application has users and tasks created by users. Users can also create a task and assign another user to it. I am not quite sure how to build associations here.
I know since a task is created by a user, I can have an association as below,
class User
has_many :tasks, dependent: :destroy, foreign_key: :user_id
end
class Task
belongs_to :user
end
I also want to add an association for creator in the Task model but I am not sure how to do it since a creator will also be an instance of the User class and I already have a belongs_to association with User
I tried to add an association for creator in Task model in the following way but it didn't work.
has_one :user, foreign_key: :creator_id, class_name: "User"
Since you've already defined the belongs_to :user method, the method #task.user is already taken by that association. You can't use the same name for a different method, so you'll have to use a different name for that association.
The association name doesn't have to be the same as the model. You can name the creator association something else, like "creator":
has_one :creator, foreign_key: 'creator_id', class_name: "User"
Since the task has a foreign key for the creator, you should be able to use belongs_to for both associations:
class Task
belongs_to :user
belongs_to :creator, foreign_key: 'creator_id', class_name: 'User'
end
Here's a discussion about the difference between has_one and belongs_to: What's the difference between belongs_to and has_one?
Either way way you can do:
#task.user # the User who is assigned the task
#task.creator # the User who created the task

Structuring Rails models for different kinds of data

I need an opinion about how to structure my models for a rails 4 app I'm doodling on. The architecture shouldn't be too hard but I've been going in circles for hours so I'll throw it out to the community.
I have a model called "checkin" that has_many "fields". Each field can have many values that can be one of several data types that may increase in number over time but for starters will be just float and string. Once a field is added to a checkin its data type cannot change.
Think of a checkin for losing weight where some people would want to log just weight. Others might want to log weight, %bodyfat. Others might want extra fields for other metrics or a text field for what mood you're in.
So what I've got so far is:
class Checkin < ActiveRecord::Base
has_many :fields
class Field < ActiveRecord::Base
belongs_to :checkin
And then I was going to do
class DataFloat < ActiveRecord::Base
belongs_to :field
class DataString < ActiveRecord::Base
belongs_to :string
etc.
The schema is simple with just references for now. DataFloat has a float and DataString has a string (as you'd expect)
Then I'll use something like ActiveRecord::Base.descendants a (as per THIS) to create a select box so that you can choose what a field is when you add it to the checkin.
My question for all those MVC experts out there is whether or not this is the best way to do this. Would I be better off having a central object "Data" that is extended by DataFloat and DataString? Is there a third, better way I haven't thought of?
Anyone...... bueller?
I managed to solve it but it took a long time to find the correct term for what I was trying to do. It's basically polymorphic associations in reverse.
There's a fantastic tutorial by Rune Madsen here:
https://gist.github.com/runemadsen/1242485
basically I do it this way:
class Field < ActiveRecord::Base
has_many :field_datas
has_many :data_ints, :through => :field_datas, :source => :data_object, :source_type => 'DataInt'
has_many :data_floats, :through => :field_datas, :source => :data_object, :source_type => 'DataFloat'
.... etc.....
Then I do:
class FieldData < ActiveRecord::Base
belongs_to :field
belongs_to :data_object, :polymorphic => true
end
And then finally the actual data which is a table with an id and one column:
class DataInt < ActiveRecord::Base
has_one :field_data, :as =>:data_object
has_one :field, :through => :datas
And then there would be a DataType class for each data type.
I think I will probably need to write special handlers to make sure everything gets destroyed and created properly but overall I'm pretty pleased with it.
I would love to know if anyone has an opinion about doing it this way.

Finding a model instance with no relation in Rails

class User
has_one :settings
class Settings
belongs_to :user
I want to do something like
#user_with_no_settings = User.where(:settings => nil)
But this returns an empty relation.
How do I find all users which don't have a settings related to them? (So I will find them and create them)
Most importantly, your association is incorrect;
Change it to:
class User
has_one :setting
class Settings
belongs_to :user
The Class name is plural but the association has_one is always singular. So you can't use :settings for has_one as oppose to has_many which is always plural.
Use this:
User.where("id not in (select user_id from settings)")
The above query will give all the users which don't have a settings associated to them.
Okay. In your situation you may need some TRY this code.
User.where('id NOT IN (?)', User.joins(:settings).pluck('settings.user_id'))
But, you need to follow Rails Convention.
Change settings to setting.

Unique Association :through

I have a many to many :through relationship between a set of classes like so:
class Company
has_many :shares
has_many :users, :through => :shares, :uniq => true
end
class User
has_many :shares
has_many :companys, :through => :shares, uniq => true
end
class Share
belongs_to :company
belongs_to :user
end
I want to ensure a unique relationship so that a user can only have one share in any one company, which is what I have tried to achieve using the "uniq" argument.
At first I thought this was working, however it seems the behaviour os the "uniq" is to filter on the SELECT of the record, not pre-INSERT so I still get duplicate records in the database, which becomes an issue if I want to start dealing with the :shares association directly, as calling user.shares will return duplicate records if they exist.
Can anyone help with an approach which would force truely uniq relationships? so that if I try adding the second relationships between a user and a company it will reject it and only keep the original?
Have you tried adding this to your Share class?
validates_uniqueness_of :user, scope: :company
Also, in your User class I think it should be:
has_many :companies, through: :shares
I hope that helps.

Undefined Method on has_many :through

I have three models:
Class Project < ActiveRecord::Base
has_many :tasks
has_many :tags, :through => :tasks
end
Class Tasks < ActiveRecord::Base
belongs_to :project
has_and_belongs_to_many :tags
end
Class Tags < ActiveRecord::Base
has_and_belongs_to_many :tasks
has_many :projects, :through => :tasks
When I open up console, I can get my Project and Task information as expected:
Tag.find(1).projects
Tag.find(1).tasks
If I want, I can get all the tasks for each project regardless of the tag:
Project.find(1).tasks
For whatever reason, I can't access tasks if I get projects by tag...
something = Tag.find(1).projects
something.tasks
...I get the error:
undefined method `tasks' for #<ActiveRecord::Relation:0x007feae4af0e70>
I've looked for a couple hours and can't find anything that corrects this problem. Based on everything I've found, it should be working... but it's not.
I'm using Rails 3.2.3.
Shouldn't Tag.find(1).tasks give you the same result?
Anyway, the problem you're facing is that you're trying to retrieve an association from a Relation object instead of an instance of your model. Relations can be used to chain query conditions, but you can't directly reference associations from them. So, to get your example working, you'd need to do
p = Tag.find(1).projects.includes(:tasks)
Then reference tasks like this: p[0].tasks.
However I'd just make sure that Tag.find(1).tasks will generate the same SQL and ultimately return the same collection of tasks.