This has something to do with my last quesion about unsaved objects, but now it is more about a specific problem how to use rails.
The models I have are:
class User < ActiveRecord::Base
has_many :project_participations
has_many :projects, through: :project_participations, inverse_of: :users
end
class ProjectParticipation < ActiveRecord::Base
belongs_to :user
belongs_to :project
enum role: { member: 0, manager: 1 }
end
class Project < ActiveRecord::Base
has_many :project_participations
has_many :users, through: :project_participations, inverse_of: :projects
accepts_nested_attributes_for :project_participations
end
With this models, when I create a new project I can do it by a form (fields_for
etc) and then I can call update_attributes
in the controller. So if I have users in the database already, I can do this:
u = Users.create # save one user in database (so we have at least one saved user)
p = Project.new
# add the user to the project as a manager
# the attributes could come from a form with `.fields_for :project_participations`
p.update_attributes(project_participations_attributes: [{user_id: u.id, role: 1}])
=> true
This works fine until I want to do something with the users
of a project. For example I want add a validations that there must be at least one user
for a project:
class Project < ActiveRecord::Base
...
validates :users, presence: true # there must be at least one user in a project
...
end
This now gives:
u = Users.create
p = Project.new
p.update_attributes(project_participations_attributes: [{user_id: u.id, role: 1}])
=> false
p.errors
=> #<ActiveModel::Errors:... @base=#<Project id: nil>, @messages={:users=>["can't be blank"]}>
p.users
=> #<ActiveRecord::Associations::CollectionProxy []>
p.project_participations
=> #<ActiveRecord::Associations::CollectionProxy [#<ProjectParticipation id: nil, user_id: 1, project_id: nil>]>
So on unsaved projects
the .users
is empty. This already bugs me (see my last quesion about unsaved objects). But in this case I can of course now work around this by doing validates :project_participations, presence: true
instead of validates :users, presence: true
and it should mean the same.
But this would mean I should never use the .users
method (in any helper, model, view, ...) unless I am totally sure that I work with a saved object. Which in fact renders the .users
method unusable (like it does with the validation of user`s presence).
If I call update_attributes
like this, the validations works and it saves:
p.update_attributes(users: [u])
With this it creates the project_participation
by itself so p.users
works as expected. But here I cannot set any data like role
for project_participation
of that user.
So my questions are: Can I make the .users
method work whether or not the object is saved (I think not)? But then, how can I add users to a unsaved project as a manager/member and work with the unsaved project?
I hope my problem is clear.
I think I understand you question, and you're correct in assuming that you cannot use the
.users
method whether or not theproject
model is saved. The reason for this is that in defining an association inProject
(ie.has_many :users, through: :project_participations, inverse_of: :projects
) you're telling rails to read theusers
attribute out of the database via theproject_participations
join table and when you haven't saved the project you have nothing to read out of the database.In order to add a
User
to your project in a particular role you will need to create a newProjectParticipation
model which you will then associate to your project. If you then remove theusers
association and write your ownusers
method you should be able to access your collection of users regardless of whether or not the project has been saved.Then something like:
Hopefully that helps.