Relationships in Model Ruby on Rails - sql

I have a View called View_CrossReference in Sybase. I want to create Model for this view.
This table has a column called Answer.
I have an another table and model called SurveyXref. In this table i have a column
called Answer_No.
I want to create a relationship between these models and get the data from Answer column from View_CrossReference and display into my grid in SurveyXref page.

IN view_crossreference model
has_one :survey_xrefs, :primary_key => :answer, :foreign_key =>
:answer_no
In survey_xrefs model
belongs_to :view_crossreference, :primary_key => :answer ,
:foreign_key => :answer_no
now simply in controller u can access
v.view_crossreference.answer

Without "Model", means you have created table via stand alone migration.
Could you please show me your code for better understanding?

Related

Retrieving sublist 3 level deep in Rails

I have a datamodel that contains a Project, which contains a list of Suggestions, and each Suggestion is created by a User. Is there a way that I can create a list of all distinct Users that made Suggestions within a Project?
I'm using Mongoid 3. I was thinking something like this, but it doesn't work:
#project = Project.find(params[:id])
#users = Array.new
#users.push(#project.suggestions.user) <-- this doesn't work
Any ideas? Here's my model structure:
class Project
include Mongoid::Document
has_many :suggestions, :dependent => :destroy
...
end
class Suggestion
include Mongoid::Document
belongs_to :author, class_name: "User", :inverse_of => :suggestions
belongs_to :project
...
end
class User
include Mongoid::Document
has_many :suggestions, :inverse_of => :author
...
end
While Mongoid can give MongoDB the semblance of relationships, and MongoDB can hold foreign key fields, there's no underlying support for these relationships. Here are a few options that might help you get the solution you were looking for:
Option 1: Denormalize the data relevant to your patterns of access
In other words, duplicate some of the data to help you make your frequent types of queries efficient. You could do this in one of a few ways.
One way would be to add a new array field to User perhaps called suggested_project_ids. You could alternatively add a new array field to Project called suggesting_user_ids. In either case, you would have to make sure you update this array of ObjectIds whenever a Suggestion is made. MongoDB makes this easier with $addToSet. Querying from Mongoid then looks something like this:
User.where(suggested_project_ids: some_project_id)
Option 2: Denormalize the data (similar to Option 1), but let Mongoid manage the relationships
class Project
has_and_belongs_to_many :suggesting_users, class_name: "User", inverse_of: :suggested_projects
end
class User
has_and_belongs_to_many :suggested_projects, class_name: "Project", inverse_of: :suggesting_users
end
From here, you would still need to manage the addition of suggesting users to the projects when new suggestions are made, but you can do so with the objects themselves. Mongoid will handle the set logic under the hood. Afterwards, finding the unique set of users making suggestions on projects looks like this:
some_project.suggesting_users
Option 3: Perform two queries to get your result
Depending on the number of users that make suggestions on each project, you might be able to get away without performing any denormalization, but instead just make two queries.
First, get the list of user ids that made suggestions on a project.
author_ids = some_project.suggestions.map(&:author_id)
users = User.find(author_ids)
In your Project class add this :
has_many :users, :through => :suggestions
You'll then be able to do :
#users.push(#project.users)
More info on :through here :
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many
For mongoid, take a look at this answer :
How to implement has_many :through relationships with Mongoid and mongodb?

Rails - two foreign keys on one model both refer to same model

I'm fairly new to ActiveRecord associations. I'm sketching out an application that tracks who owes each other money among a set of users. An Expense model and a User model seem like natural choices, I'm just not sure how to define the relationship between the two. For example, I want to track the creditor ("owner") and the debtor of each expense, but that's really just two foreign keys that go back to User. In addition, each user can have multiple expenses (both as creditor and debtor) My best guess for the associations thus far is something like:
class Expense
# belongs_to or has_one here?
# Not sure about class => User syntax:
# need to alias to foreign keys that reference the same model
belongs_to :creditor, :class => User
belongs_to :debtor, :class => User
class User
# has_many expenses defines a creditor relationship (user owns expense)
# how to define debtor relationship? (belongs_to...?)
has_and_belongs_to_many :expenses
I've read the Rails guide on associations but I'm still fairly lost on foreign keys and join tables. Any input is much appreciated!
So this is definately not a has_and_belongs_to_many thats for many-to-many relationships. You just need to use a couple has_many relationships. I think it should end up looking like this:
Edit: oops I fudged that a bit that up sorry let me have another go:
class Expense
# make sure expense table has 'creditor_id' and 'debtor_id' rows
belongs_to :creditor, :class_name => "User", :foreign_key => :creditor_id
belongs_to :debtor, :class_name => "User", :foreign_key => :debtor_id
class User
has_many :debts, :class_name => "Expense", :foreign_key => :debtor_id
has_many :credits, :class_name => "Expense", :foreign_key => :creditor_id
The other answers tell you what you need to do, but it can be kind of confusing to people who are new to Rails, as I am, to piece all these things together, so here is a complete solution, including both Migrations and Models.
Also, as a side note: I prefer Loans, Lender and Borrower to Expense, Creditor and Debtor, or Debt, Creditor and Debtor. Mostly because Expense is ambiguous and Debt is too similar to Debtor. But it's not that important; just do what makes sense to you, since you will be maintaing your code.
Migrations
class CreateLoans < ActiveRecord::Migration
create_table :loans do |t|
def up
t.references :lender
t.references :borrower
end
end
end
Here you are specifying that there are two columns in this table that will be referred to as :lender and :borrower and which hold references to another table. Rails will actually create columns called 'lender_id' and 'borrower_id' for you. In our case they will each reference rows in the Users table, but we specify that in the models, not in the migrations.
Models
class Loan < ActiveRecord::Base
belongs_to :lender, class_name => 'User'
belongs_to :borrower, class_name => 'User'
end
Here you are creating a property on the Loan model named :lender, then specifying that this property is related to the User class. Rails, seeing the 'belongs_to', will look for a column in the loans table called 'lender_id', which we defined above, and use that to store the foreign key. Then you're doing the exact same thing for the borrower.
This will allow you to access your Lender and Borrower, both instances of the User model, through an instance of the Loan model, like this:
#loan.lender # Returns an instance of the User model
#loan.borrower.first_name # Returns a string, as you would expect
As a side note: the 'belongs_to' nomenclature makes decent sense in this case, but can be kind of confusing elsewhere. Just remember that it is always used on whichever thing contains the foreign key.
class User < ActiveRecord::Base
has_many :loans_as_lender, :class_name => 'Loan', :foreign_key => 'lender_id'
has_many :loans_as_borrower, :class_name => 'Loan', :foreign_key => 'borrower_id'
end
Here you are creating a property on the User model named :loans_as_lender, specifying that this property is related to the Loan model, and that the foreign key on the Loan model which relates it to this property is called 'lender_id'. Then you are doing the same thing for :loans_as_borrower.
This allows you to get all the loans where a User is the lender or borrower, like this:
#address.loans_as_lender
#address.loans_as_borrower
Doing either of these will return an array of instances of the Loan model.
If your expense migration looks like this:
create_table :expenses do |t|
t.integer :creditor_id, :null => false
t.integer :debtor_id, :null => false
# other attributes here
end
then your Expense model is sufficient. If you take a look at the documentation for belongs_to, you'll see that it will correctly infer the foreign keys into the user table:
:foreign_key
Specify the foreign key used for the association. By default this is guessed to be the name of the association with an “_id” suffix. So
a class that defines a belongs_to :person association will use
“person_id” as the default :foreign_key. Similarly, belongs_to
:favorite_person, :class_name => "Person" will use a foreign key of
“favorite_person_id”.
So you don't need to explicitly specify a foreign key here. If you use other naming conventions for the ids in your expenses model, then you need to explicitly specify them in your associations.
For your User model, you don't have a many_to_many relationship with expenses - an expense always belongs to exactly one debtor and exactly one creditor. So all you need is two has_many associations:
has_many :debts, :class_name => 'Expense', :foreign_key => :debtor_id
has_many :credits :class_name => 'Expense', :foregin_key => :creditor_id

Ruby on Rails: has_many referential --which model objects does it own?

I am new to Rails and finished Michael Hartl's "Ruby on Rails 3 Tutorial". Although the book teaches me a lot, I find this puzzle I don't understand.
To preview the puzzle, that is, I don't understand, inside User model,
has_many :following, :through=>:relationship, :source=>:followed
how this piece of code link "user.following" to an array of User instances.
And below is the whole puzzle.
First of all, I have the Relationship model, which records followed_id and follower_id infos. Inside Relationship model, the association is simple as
class Relationship < ActiveRecord::Base
attr_accessible :followed_id
belongs_to :follower, :class_name => "User"
belongs_to :followed, :class_name => "User"
end
Then, inside the User model, a user will assume the role of follower, and collect all its following rows in relationships table through relationships association.
class User < ActiveRecord::Base
.
.
.
has_many :relationships, :foreign_key => "follower_id", :dependent => :destroy
.
Until now, I got it.
But confusion came at the next line, where through user.following it can assemble all that user's following(User instances). Like so,
has_many :following, :through=>:relationships, :source=>:followed
I understand that :source=>:followed will overwrite the default, and let find all followed_ids associated with that user.
But, how can Rails recognize followed_id to link to User object? The label name doesn't match users, nor is there :class_name specified. I just don't get how Rails do this underlying work, or I missed out some hints.
Thank you! :)
But, how can Rails recognize followed_id to link to User object? The
label name doesn't match users, nor is there :class_name specified. I
just don't get how Rails do this underlying work, or I missed out some
hints.
Rails recognize that is an user object because it is set in Relationship's belongs_to. What Rails does here is to follow the relationship class through the foreign key "follower_id" and returning every User that has a relationship with the current user as followed. Of course Rails do that in a single SQL statement like this:
SELECT `users`.* FROM `users` INNER JOIN `relationships` ON `relationships`.followed_id = `users`.id WHERE ((`relationships`.follower_id = <the current user id> ))
has_many :following, :through=>:relationships, :source=>:followed
This explains to Rails that following is the inverse relationship of following and that users has many following and followed through his relationships.
The way Rails knows that followed_id is linked to User is that it is defined in your Relationship model.
Hope you've understood ! Good luck :)

model has two attributes that belong to another model

I have a model as follows:
Greeting
belongs_to :icon
belongs_to :icon, :foreign_key => :user_icon
I need to save the icon_id and also the user_icon id in the case I don't have a registered user.
Is this correct? Will I be able to access the icon by doing the following:
#greeting.icon.name
#greeting.user_icon.name
I want to improve this question so let me explain it better:
I want to save two objects from the same model in another model.
So Greeting belongs to Icon but I will have two fields in the Greetings table for foreign keys from the Icons table but labeled differently.
I call one foreign key attribute icon_id and the other user_icon_id.
To do this is the following correct:
Greeting
belongs_to :icon
belongs_to :icon, foreign_key => :user_icon_id
Almost correct, you need something like this:
belongs_to :icon
belongs_to :user_icon, :class_name => "Icon", foreign_key => :user_icon_id
If you change the name of the field in a has_one, has_many or belongs_to association in such a way that Rails can't convert it into a model name, you need to tell Rails which model you actually mean, hence the :class_name.
Nope. You need
belongs_to :user_icon, :foreign_key => :user_icon
If you want to have a greeting.user_icon accessor using the foreign key user icon in your database.

looping through a rails data object from the controller

I have called a function from a class to find all the items related to a particular ID in a many to many HABTM relationship.
Procedures -> Tasks with a join table: procedures_tasks
I call the information like #example = Procedure.get_tasks(1,1)
I would like to be able to iterate through the data returned so that I can create an instance of each task_id related to the procedure in question
def self.get_tasks(model_id, operating_system_id)
find(:first, :select => 'tasks.id, procedures.id', :conditions => ["model_id = ? AND operating_system_id = ?", model_id, operating_system_id], :include => [:tasks])
end
I tried rendering the data as i normally would and then using .each do |f| in the view layer, but i get:
undefined method `each' for #<Procedure:0x2b879be1db30>
Original Question:
I am creating a rails application to track processes we perform. When a new instance of a process is created I want to automatically create rows for all the tasks that will need to be performed.
tables:
decommissions
models
operating_systems
procedures
tasks
procedures_tasks
host_tasks
procedures -> tasks is many to many through the procedures_tasks join table.
when you start a new decommissioning process you specify a model and OS, the model and OS specify which procedure you follow, each procedure has a list of tasks available in the join table. I am wanting to create a entry in host_tasks for each task relevant to the procedure relevant to the decommission being created.
I've done my head in over this for days, any suggestions?
class Procedure < ActiveRecord::Base
has_and_belongs_to_many :tasks
#has_many :tasks, :through => :procedures_tasks
# has_many :procedures_tasks
belongs_to :model
belongs_to :operating_system
validates_presence_of :name
validates_presence_of :operating_system_id
validates_presence_of :model_id
def self.get_tasks(model_id, operating_system_id)
find(:first, :select => 'tasks.id, procedures.id', :conditions => ["model_id = ? AND operating_system_id = ?", model_id, operating_system_id], :include => [:tasks])
end
end
the get_tasks method will retrieve the tasks associated with the procedure, but I don't know how to manipulate the data pulled from the database in rails, I haven't been able to access the attributes of the returned object through the controller because they haven't been rendered yet?
ideally i would like to be able to format this data so that I only have an array of the task_id's which i can then loop through creating new rows in the appropriate table.
It wasn't looping through because I was using the :first option when finding the data. I changed it to :all which allowed me to .each do |f| etc.
Not the best option, but there will only ever be one option anyway, so it won't cause a problem.