I'm trying to understand how I would go about storing the ID of one model record in a separate active record table (in this case the user table) when it gets created.
Basically, I have two models. A user which has_many :taxes and a tax model which belongs_to: user. In my application a user can only have one tax record, which currently I'm achieving by storing the user.id in a column in the tax model, and checking in a before filter to see if the user already has already created a tax record (which checks to see if their user.id is in the table.)
create_table "taxes", force: true do |t|
t.integer "user_id"
t.integer "income"
t.integer "taxes"
.....
Keep in mind this is all currently in an index action, which is kind of pointless since a user can only have one tax record, and only view their own tax records. It should be done with the show action I assume.
Now here's the problem, when a user creates their single tax record, the tax model is setup like this, all interacting with the taxes active record table:
def store_raw_taxes
tax = Tax.new(user_id: user.id, income: income, taxes: taxes, rrsp: rrsp)
tax.save
end
In order to use show (and check to see if the user already has created a tax record), I want to store the tax_id in the actual User's table in their row. I have created a migration AddTaxIdToUsers which made a reference and added a column called tax_id to the users table.
I don't know how to store the created tax record's ID in the user table though. This is a 2 way relationship I guess, but I don't understand how in my store_raw_taxes function, I would also interact with the User model. I guess it would be done in a after_save callback?
Would I also need to add belongs_to: tax to the user model in that case?
I would go a bit differently.
In a one-to-one relation you don't need the belongs_to definition, but the has_one
The conceptually right way to do it, in my point of view, would be:
user.rb:
has_one :tax
Then, your method would be
#user=User.find(..)
#user.build_tax(income: income, taxes: taxes, rrsp: rrsp)
Basically, I have two models. A user which has_many :taxes and a tax model which belongs_to: user. In my application a user can only have one tax record
If a user can only have one tax record, then you should not use has_many :taxes but has_one :tax instead. Rails will handle everything automatically.
See http://guides.rubyonrails.org/association_basics.html#the-has-one-association
Then you won't need "before filter to see if the user already has already". However is you want to ensure that user have a tax record at all times you can validates_presence_of :tax
See http://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html#method-i-validates
It is possible, if you use nested form, that you don't need TaxesController at all.
Also if you use nested form you will be using accepts_nested_attributes and therefore will not need your store_raw_taxes method anymore
See http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html
Related
Before destroying a record, I'd like to check if there are any uses of it on other tables, even if the record itself has no knowledge of said uses.
For example, lets say I have a table of cost_centers, and I have a table of areas.
An area has a default cost_center. cost_centers have no connection with areas.
Which kind of validation can I use in order to prevent the user from destroying a cost_center, in order to keep an area consistent?
In other words, how can I search through the database to find out wether that record is a foreign key of some other record on any other tables?
When you designed your database, you've probably set all the references up.
In your migrations, it would look like this: t.references :cost_center.
If so, your Cost Center Model could have a has_one relationship to each table holding the reference which, in your example, would be has_one :area.
Then, to check if it is actually used, you could have a before_destroy callback to a method that checks if any has_one definition is not null:
class CostCenter < ActiveRecord::Base
has_one :area
before_destroy :check_usage
def check_usage
!self.area.nil?
end
end
This might be a very question, but I'm trying to allow only unique records for a table called "Favorites" with attributes "lightbulb_id" and "student_id." I know about model validations
class Person < ActiveRecord::Base
validates_uniqueness_of :user_name
end
But, I want to validate the uniqueness of the entire record (so the combination of lightbulb_id and student_id). So, lightbulb_id and student_id can be duplicated (a student can "favorite" multiple lightbulb_id's) and consequently the same student_id can appear multiple times in the Favorites table with different lightbulb_ids. But the specific combination shouldn't be duplicated (a student cannot favorite a lightbulb twice)
This might be a very basic question, any suggestions would be appreciated. Thanks.
You can try following validation rule:
validates_uniqueness_of :student_id, scope: [:lightbulb_id]
i have 3 model society and user now Society is manage by the admin model what happens is that when the user registers, the users "id" must be save simultaneously in the society models user_id field it has to happen with in the user_controller's create action
can somebody give me a simple code to do this
many thanks
To have your user_id assigned to the society, you should set up an association between User and Society. If has_one is the wrong association, please do some research on what type of association these need to be.
# app/models/user.rb
after_create :socialize
has_one :society
def socialize
self.society.create
end
References
Callbacks
Associations
I have a Boat Model and its Models such as Brand, Model and Year. I have also User model and I would like to connect them by adding migrations to User model of boat_id and I added belongs_to :boat and has_many :boats to User model. But I can not reach User.first.boat.name from the console even though I am able to reach Boat.first.brand.name.
When I try User.first.boat.name. Console gives an error saying;
NoMethodError: undefined method `boat' for #<User:0x0000000665dc30>
Btw: Boat Model includes model_id brand_id and year_id.
EDIT1:
Or should i remove Boat model and add model_id brand_id and year_id to User model directly.
EDIT2:
I would like to be able to reach User.first.boat.brand.name or User.first.boat.year.nameor User.first.boat.model.name
EDIT3:
Every boat has one brand, year and model. But user can have many boats
EDIT4:
What i will do is;
User can sign up and login
Then User press the link list my boat.
He/she saves the boat then the page renders to User Profile
In the User profile I do not know how to get current user boat name year etc. That is why I am confused. Sorry for the misunderstanding
I think you're confused about how Rails associations work in conjunction with how they are stored in the database. If a User can have many boats, then the foreign key needs to be on the boats table. Currently you have boat_id in the users table, this should be removed and a user_id column needs to be added to the boats table as per Matt's answer.
Reference
To achieve what you're trying to do, you'll need to setup your models in the following manner:
class User
has_many :boats
...
end
class Boat
belongs_to :user # table has a user_id column
...
end
Then you can access a boat's brand using user.boats.first.brand.name
Run rails generate migration, then fill in the change method as follows:
def change
add_column :boats, :user_id, :integer
end
Then run rake db:migrate.
You user model has_many boats, so you need the boats table to refer to users. It's probably worth reading the Rails guide for ActiveRecord associations to get a better feel for how this works: http://guides.rubyonrails.org/association_basics.html#the-has-many-association
I have few question that bugs me off and need to be answered. Everything is related to the following tutorial Two Many-to-Many
Question 1
Does the join table using has_many need to have an id? or its best practice to remove the id? and add an index and using the two other primary key and set it unique and together?
Question 2
How can it be done in the migration of creating a table?
Question 3
After doing these relationship model and updating the data. I would like to create a new set of data everytime it is updated (to preserve the data). How would a controller would look in the update, new, create model?
Question 4
In the the middle table, I would like to set attributes such has a visible true, or false, how can I set also not just the third table but also the second table arguments
First ... a word of caution: That railscast is very old. There may be syntactical things in that episode that have been dated by new versions of rails.
Question 1
If you are using the has_many through method then you have to have an id column in the join model because you are using a full blown model. As Ryan mentions in the episode, you'll choose this method if you need to track additional information. If you use the has_and_belongs_to_many method, you will not have an id column in your table.
If you want to achieve a check where you do not allow duplicates in your many-to-many association (ie allow the pairing of item a with item b and again allowing another record of item a to item b), you can use a simple validates line with a scope:
validates_uniqueness_of :model_a_id, :scope => [:model_b_id]
Question 2
You can add indices in your migrations with this code
add_index :table_name, [ :join_a_id, :join_b_id ], :unique => true, :name => 'by_a_and_b'
This would be inserted into the change block below your create_table statement (but not in that create_table block). Check out this question for some more details: In a join table, what's the best workaround for Rails' absence of a composite key?
Question 3
I'm not completely clear on what you're looking to accomplish but if you want to take some action every time a new record is inserted into the join model I would use the after_create active record hook. That would look something like this.
class YourJoinModel < ActiveRecord::Base
after_create :do_something
def do_something
puts "hello world"
end
end
That function, do_something, will be called each time a new record is created.
Question 4
Using the has_many through method will give you access to the additional attributes that you defined in that model on both sides of the relationship. For example, if you have this setup:
class Factory < ActiveRecord::Base
has_many :widgets, :through => :showcases
end
class Widget < ActiveRecord::Base
has_many :factories, :through => :showcases
end
class Showcases < ActiveRecord::Base
belongs_to :factory
belongs_to :widget
attr_accessiable :factory_id, :widget_id, :visible
end
You could say something like
widget = Widget.first
shown = widget.showcases
shown.first.visible
or
shown = widget.showcases.where( :visible=> true )
You can also reach to the other association:
shown.first.factory
The reason for having an id column in an association is it gives you a way of deleting that specific association without concerning yourself with the relationship it has. Without that identifier, associations are hard to define outside of specifying all foreign keys.
For a trivial case where you have only two components to your key, this isn't that big a differentiator, but often you will have three or more as part of your unique constraint and there's where things get tricky.
Having an id also makes the relationship a first-class model. This can be useful when you're manipulating elements that have associated meta-data. It also means you can add meta-data effortlessly at a later date. This is what you mean by your "Question 4". Add those attributes to the join model.
Generally the join model is created like you would any other model. The primary key is the id and you create a series of secondary keys:
create_table :example_things |t|
t.integer :example_id
t.integer :thing_id
end
add_index :example_joins, [ :example_id, :thing_id ], :unique => true
add_index :example_joins, :thing_id
The main unique index serves to prevent duplication and allows lookups of key-pairs. The secondary serves as a way of extracting all example_id for a given thing_id.
The usual way to manipulate meta-data on the join model is to fetch those directly:
#example_things = #example.example_things.includes(:thing)
This loads both the ExampleThing and Thing models associated with an Example.