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
Related
I have two models that both accept_nested_attributes_for each other. I know this is causing issues with rails_admin but can't seem to figure out the appropriate command to exclude nested attributes in my configuration. Ideally I would like to exclude nested attributes for all models so that this problem does not happen again.
Branden,
You need to inform the bi-direction association using inverse_of:
Ex:
class User < ActiveRecord::Base
belongs_to :company, :inverse_of => :users
accepts_nested_attributes_for :company
end
For both sides of association:
class Company < ActiveRecord::Base
has_many :users, inverse_of: :company
accepts_nested_attributes_for :users, :allow_destroy => true
end
More information in the docs: http://guides.rubyonrails.org/association_basics.html#bi-directional-associations
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.
I've built a simple address book application in my intro Ruby on Rails class with separate models for street addresses (Address), email addresses (Email), and web addresses (Web) using nested forms using a single controller (Entry). I'd like to now change the last two models (Email and Web) to use single table inheritance from a base Url table. Is that preferable (or even possible) compared to rebuilding the app from scratch with the correct inheritance relationships?
I've included my existing models below:
class Entry < ActiveRecord::Base
attr_accessible :first_name, :last_name, :addresses_attributes, :webs_attributes, :emails_attributes
has_many :addresses, dependent: :destroy
has_many :emails, dependent: :destroy
has_many :webs, dependent: :destroy
accepts_nested_attributes_for :addresses, :emails, :webs, allow_destroy: true, reject_if: :all_blank
end
class Address < ActiveRecord::Base
belongs_to :entry
belongs_to :address_type
attr_accessible :address_type_id, :city, :state, :street, :zip
end
class Email < ActiveRecord::Base
belongs_to :entry
belongs_to :address_type
attr_accessible :address_type_id, :email, :entry_id
validates_email_format_of :email
end
class Web < ActiveRecord::Base
belongs_to :entry
belongs_to :address_type
attr_accessible :address_type_id, :web, :entry_id
end
How would changing
class Email < ActiveRecord::Base
and
class Web < ActiveRecord::Base
to
class Email < Url
and
class Web < Url
affect my existing application?
Thanks in advance for your help and advice.
Be sure to also add the Url class that's inheriting the ActiveRecord::Base class.
class Url < ActiveRecord::Base
belongs_to :entry
belongs_to :address_type
attr_accessible :address_type_id :entry_id
end
class Email < Url
attr_accessible :email
validates_email_format_of :email
end
class Web < Url
attr_accessible :web
end
also add the extra line to your entry.rb:
has_many :urls, dependent: :destroy
It is possible to generate a migration that sets up the single table inheritance, but I was unfortunately not able to do this successfully without breaking other things in my app. I went ahead and restarted fresh with a new application and correctly implemented the proper inheritance. This was in the interests of time and the practice of building an application from scratch. In a real-world environment, I'm sure it would be worth investing the time to create the proper migration and changes to the various dependencies.
Thanks Zippie for your advice. I appreciate it.
I'm currently working on a small project using Ruby On Rails 3.2 to create a database that contains several unique Models. Each Model has many Elements and each Element has the potential to belong to many Models. I have been able to set up the models in the following manner:
class Model < ActiveRecord::Base
has_many :model_elements
has_many :elements, :through => :model_elements
attr_accessible :elements, :name, :notes, :ref
end
class Element < ActiveRecord::Base
has_many :model_elements
has_many :models, :through => :model_elements
attr_accessible :elementType, :name, :notes, :ref
validates_presence_of :name
end
class ModelElement < ActiveRecord::Base
belongs_to :Model
belongs_to :element
attr_accessible :model_id, :created_at, :element_id
end
My question is how do I add multiple Elements to a single Model? I've tried to find some documentation but I can't find anything. Currently I'm trying to do the following:
#model.elements = #element
Where #element is a predefined element however it's throwing the following error:
undefined method `each' for #<Element:0x007ff803066500>
Any help would be greatly appreciated.
Try
#model.elements << #element
collection.create(attributes = {})
Returns a new object of the collection type that has been instantiated with attributes, linked to this object through the join table, and that has already been saved.
#model.elements.create(:name => "example")
Amar's answer is correct. If you wanted you can simplify your models further by using the has_and_belongs_to_many association.
class Model < ActiveRecord::Base
has_and_belongs_to_many :elements, :join_table => :model_elements
end
class Element < ActiveRecord::Base
has_and_belongs_to_many :models, :join_table => :model_elements
end
#model.elements << #element
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