Has-Many and Belongs-to-one Relation - ruby-on-rails

I'm trying to keep track of how many signup_conversions a user creates.
Therefore, I have those two following models:
signup_conversion.rb
class SignupConversion < ActiveRecord::Base
belongs_to :user
belongs_to :convertee, :class_name => "User", :foreign_key => 'convertee_id'
attr_accessible :convertee_id
end
user.rb
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation
belongs_to :signup_conversion
has_many :signup_conversions
end
Would this work that way? Or am I missing something crucial here?

I haven't tried the code, but I give you some tips that hope you find useful.
I think every has_many/has_one statement should have its correspondent belongs_to, so three belongs_to and one has_many doesn't look good.
I'm not sure has_one :signup_conversion and has_many :signup_conversions would play well together, so I'd rather change the names. I changed the other names as well to try to make the associations clearer although I'm not sure I fully understand the real concepts they represent. You will probably come up with better names.
By default, the foreign key is guessed adding the suffix _id to the association name, so you don't need to specify it in this case. Also, I don't think you need to make that attribute accessible, at least not for the association to work.
signup_conversion.rb
class SignupConversion < ActiveRecord::Base
belongs_to :owner , :class_name => "User"
belongs_to :convertee, :class_name => "User"
end
user.rb
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation
has_one :owned_signup_conversion , :class_name => "SignupConversion"
has_many :triggered_signup_conversions, :class_name => "SignupConversion"
end

You have more code than you need here; you only need
class SignupConversion < ActiveRecord::Base
belongs_to :user
end
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation
has_many :signup_conversions
end
Then you need a user_id column in your signup_conversions table, and you call
#user.signup_conversions
in your views or controller.

Related

Data modeling of Grandparent, Parent, and Child relationships in Rails

Is it a bad practice to set a model (table) association between both parent and child AND grandparent and child? For example, if I want to easily query a user's projects or a user's tasks, is the following setup recommended? If so, is there a good way to ensure both foreign keys always point to the same user?
Any help will be greatly appreciated.
class User < ActiveRecord::Base
attr_accessible :email, :first_name, :last_name
has_many :projects
has_many :tasks
end
class Project < ActiveRecord::Base
attr_accessible :name, :status
belongs_to :user
has_many :tasks
end
class Task < ActiveRecord::Base
attr_accessible :name, :status
belongs_to :user
belongs_to :project
end
There is nothing wrong with what you are trying to do, in fact rails has already predefined some association methods to help you. Just a couple of modifications and you are good to go
class User < ActiveRecord::Base
attr_accessible :email, :first_name, :last_name
has_many :projects
has_many :tasks, through: :projects
end
By adding the through: :projects to your tasks now means you can access all of a users tasks like so
$user = User.first #or whatever
$user.tasks
=> [AR array of all tasks]
You can play around with it in irb. In addition you don't need belongs_to :user in your Task model. It's already taken care of.
Look at section 2.4 for more details
EDIT: I have made the assumption (based upon your description) that a task belongs to a project, and a project belongs_to a user, and that user's don't have tasks directly, but through projects. If that was wrong, let me know and we'll figure it out from there.

find_or_create on a has many through relationship

I have a has many through relationship in my app:
Shows has many Bands through => Lineups
Bands are unique by :name
class Show < ActiveRecord::Base
attr_accessible :city_id, :title, :dateonly, :timeonly, :image, :canceled, :venue_attributes, :bands_attributes
belongs_to :city
belongs_to :venue
has_many :lineups
has_many :bands, through: :lineups
has_and_belongs_to_many :users
end
class Lineup < ActiveRecord::Base
belongs_to :show
belongs_to :band
end
class Band < ActiveRecord::Base
attr_accessible :name, :website, :country, :state
has_many :lineups
has_many :shows, through: :lineups
validates :name, presence: true
validates_uniqueness_of :name
before_save :titleize_name
private
def titleize_name
self.name = self.name.titleize
end
end
New Bands are created like this:
(lets say we have a show record already saved called s1)
> s1.bands.new(name: "Wet Food")
> s1.save
Right now this will only save if a band named "Wet Food" doesn't already exist
In which model is the best place to do a Band.find_or_create in this relationship so that an existing band can be used if one with the same name exists?
This is generally the type of call that would go in a Controller (or maybe a service object), but not in a Model. It really depends on the particular user flow that you're trying to accomplish in your app. Basically, where ever you are already using s1.bands.new, you could use this instead :
s1.bands.where(name: 'Wet Food').first_or_create

creating object with nested attributes

i need to create a form, which will create object which has another two objects as attributes, but those objects should be available from a dropdown list that contains templates of those objects.
class User < ActiveRecord::Base
accepts_nested_attributes_for :adresses, :profiles
end
class Address < ActiveRecord::Base
attr_accessible :city, :country
belongs_to :user
end
class Profile < ActiveRecord::Base
attr_accessible :nickname, :password
belongs_to :user
end
tricky part might be, that User has no column 'address_id' or 'profiles_id', everything should go to the Profile and Address, which are being created in the same moment as the User (they have the same attributes as their templates)
I could really use some help, dont expext full code solution, but some hints would be nice
Try this setup:
class User < ActiveRecord::Base
has_one :address
has_one :profile
accepts_nested_attributes_for :address, :profile
attr_accessible :adress_attributes, :profile_attributes
end
class Address < ActiveRecord::Base
attr_accessible :city, :country
belongs_to :user
end
class Profile < ActiveRecord::Base
attr_accessible :nickname, :password
belongs_to :user
end
See doc

Views for many to many associations [ Rails ]

I am newbie to Ruby on Rails and trying to learn this hard way , by writing my own project.
I have scenario where a test contain many problems, and problems can be reused in other tests also. So I have created models something like this.
class Test < ActiveRecord::Base
has_many :test_problems
has_and_belongs_to_many :problems
has_many :problems, :through => :test_problems
belongs_to :user
attr_accessible :name, :user_id, :reusable
end
class Problem < ActiveRecord::Base
belongs_to :user
has_many :test_problems
has_and_belongs_to_many :tests
has_many :tests, :through => :test_problems
attr_accessible :name, :statement, :input, :output, :user_id , :reusable
end
class TestProblem < ActiveRecord::Base
belongs_to :test
belongs_to :problem
attr_accessible :problem_id, :test_id
end
Now I have tested I can correctly add the association in Test Controller create after save.
#test.problems << Problem.find( :last )
I am looking for way how can user add many problems to his test when he create new one. I am unable to write the view and controller code handling this. What javascript are required. First a solution is good and then how can proceed to optimize this using partial extra would be great.
-Hemant

How to establish associations for a model with two belongs_to relationships?

I am building an application with the following model functions
Groups have many Users
Groups have many Expenses (each expense has a :name, :total, :added_by_user_id fields)
Expenses have many owings (1 for each user in the group)
Owings have an :amount and a :user_id, to reference which user the owing is referring
So far, I have set up the models as followings:
# user.rb
class User < ActiveRecord::Base
attr_accessible :first_name, :last_name, :email, :password
has_many :memberships, :foreign_key => "member_id", :dependent => :destroy
has_many :groups, :through => :memberships
has_many :owings
end
# group.rb
class Group < ActiveRecord::Base
attr_accessible :name
has_many :memberships, :dependent => :destroy
has_many :members, :through => :memberships
has_many :expenses
end
# expense.rb
class Expense < ActiveRecord::Base
attr_accessible :total_dollars, :name, :owings_attributes, :added_by_user_id
belongs_to :group, :inverse_of => :expense
has_many :owings, :dependent => :destroy
end
# owing.rb
class Owing < ActiveRecord::Base
attr_accessible :amount_dollars, :user_id
belongs_to :expense, :inverse_of => :owings
belongs_to :user, :inverse_of => :owings
end
# NB - have left off memberships class (and some attributes) for simplicity
To create an expense, I'm using #group.expenses.build(params[:expenses]), where params come from a nested model form that includes attributes for the owings that need to be created. The params include the 'user_id' for each of the 'owing' instances for that expense.
I have two concerns:
Firstly - I've made 'user_id' accessible in the owings model, meaning that a malicious user can change who owes what in an expense (I think?). I don't know how to get around this, though, because the user needs to see the names of all the other members of the group when they fill out the expense/owings form.
Secondly - I've also made 'added_by_user_id' accessible in the expense model - I also wouldn't want malicious users to be able to change this, since this user_id has special edit/delete priveleges for the expense. Is there some clever way to make an expense 'belong_to' a User AND a group, and set both of these associations when creating WITHOUT having to make either an accessible attribute? If it helps, the 'added_by_user_id' can always be set to the current_user.
Any ideas? Very possible I'm missing something fairly fundamental here.
Thanks in advance!
PS. Long time listener, first time caller. Thanks to all of you for teaching me ruby on rails to date; this website is an incredible resource!
Have you thought about setting them dynamically?
dynamic attr-accessible railscast

Resources