Mohamad El-Husseini
2012-May-01 16:05 UTC
Setting an addional attribute on the join model in a has_many through relationship
I have User, Account, and Role models. The Account model accepts nested properties for users. This way users can create their account and user records at the same time. class AccountsController < ApplicationController def new @account = Account.new @user = @account.users.build end end The above will work, but the user.roles.type defaults to member. At the time of registration, I needuser.roles.type to default to admin. This does not work: class AccountsController < ApplicationController def new @account = Account.new @role = @account.role.build # Role.type is protected; assign manually @role.type = "admin" @user = @account.users.build end end I thought about inheritance, but it really complicate things. I need roles to be dynamic so users can add their own admins and mods, and so on. I think I''m running into these issues because I''m not modeling my data modeling correctly. Accounts#new <%= simple_form_for(@account, html: { class: ''form-horizontal'' }) do |f| %> <legend>Account Details</legend> <%= render ''account_fields'', f: f %> <%= f.simple_fields_for :users do |user_form| %> <legend>Personal Details</legend> <%= render ''users/user_fields'', f: user_form %> <% end %> <%= f.submit t(''views.accounts.post.create''), class: ''btn btn-large btn-primary'' %> <% end %> Models: class User < ActiveRecord::Base has_many :roles has_many :accounts, through: :roles end class Account < ActiveRecord::Base has_many :roles has_many :users, through: :roles accepts_nested_attributes_for :users end # user_id, account_id, type [admin|moderator|member] class Role < ActiveRecord::Base belongs_to :user belongs_to :account after_initialize :init ROLES = %w[owner admin moderator member] private def init self.role = "member" if self.new_record? end end -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To view this discussion on the web visit https://groups.google.com/d/msg/rubyonrails-talk/-/Y6E7lV68ZF8J. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Mohamad El-Husseini
2012-May-01 16:10 UTC
Re: Setting an addional attribute on the join model in a has_many through relationship
My question can be succinctly put: Is it possible to set an additional attribute on the join model when usingaccepts_nested_attributes_for? On Tuesday, May 1, 2012 12:05:05 PM UTC-4, Mohamad El-Husseini wrote:> > I have User, Account, and Role models. The Account model accepts nested > properties for users. This way users can create their account and user > records at the same time. > > class AccountsController < ApplicationController > def new > @account = Account.new > @user = @account.users.build > end > end > > The above will work, but the user.roles.type defaults to member. At the > time of registration, I needuser.roles.type to default to admin. This > does not work: > > class AccountsController < ApplicationController > def new > @account = Account.new > @role = @account.role.build > # Role.type is protected; assign manually > @role.type = "admin" > @user = @account.users.build > end > end > > I thought about inheritance, but it really complicate things. I need roles > to be dynamic so users can add their own admins and mods, and so on. I > think I''m running into these issues because I''m not modeling my data > modeling correctly. > Accounts#new > > <%= simple_form_for(@account, html: { class: ''form-horizontal'' }) do |f| %> > <legend>Account Details</legend> > <%= render ''account_fields'', f: f %> > > <%= f.simple_fields_for :users do |user_form| %> > <legend>Personal Details</legend> > <%= render ''users/user_fields'', f: user_form %> > <% end %> > > <%= f.submit t(''views.accounts.post.create''), class: ''btn btn-large btn-primary'' %> > <% end %> > > Models: > > class User < ActiveRecord::Base > has_many :roles > has_many :accounts, through: :roles > end > > class Account < ActiveRecord::Base > has_many :roles > has_many :users, through: :roles > accepts_nested_attributes_for :users > end > > # user_id, account_id, type [admin|moderator|member] > class Role < ActiveRecord::Base > belongs_to :user > belongs_to :account > after_initialize :init > > ROLES = %w[owner admin moderator member] > > private > def init > self.role = "member" if self.new_record? > end > end > > >-- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To view this discussion on the web visit https://groups.google.com/d/msg/rubyonrails-talk/-/tuAoRXG8KD0J. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Colin Law
2012-May-01 20:28 UTC
Re: Setting an addional attribute on the join model in a has_many through relationship
On 1 May 2012 17:05, Mohamad El-Husseini <husseini.mel-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> I have User, Account, and Role models. The Account model accepts nested > properties for users. This way users can create their account and user > records at the same time. > > class AccountsController < ApplicationController > def new > @account = Account.new > @user = @account.users.build > end > end > > The above will work, but the user.roles.type defaults to member. At the time > of registration, I needuser.roles.type to default to admin. This does not > work: > > class AccountsController < ApplicationController > def new > @account = Account.new > @role = @account.role.build > # Role.type is protected; assign manually > @role.type = "admin" > @user = @account.users.build > end > endIt depends what you mean by ''work''. It will assign the type of @role to "admin" but the problem is that you have not saved it to the database after changing the type. By the way, I advise against using type as an attribute name, that is a reserved attribute name for use with STI.> ...> # user_id, account_id, type [admin|moderator|member] > class Role < ActiveRecord::Base > belongs_to :user > belongs_to :account > after_initialize :init > > ROLES = %w[owner admin moderator member] > > private > def init > self.role = "member" if self.new_record? > end > endShould that not be self.type (apart from the fact that type is not a good name)? But if you want a default value for a column why not just set the default in the database? Colin -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Mohamad El-Husseini
2012-May-01 21:53 UTC
Re: Setting an addional attribute on the join model in a has_many through relationship
> It depends what you mean by ''work''. It will assign the type of @role > to "admin" but the problem is that you have not saved it to the > database after changing the type. By the way, I advise against using > type as an attribute name, that is a reserved attribute name for use > with STI.I did change type to role. I get this rather mysterious error: Roles en-US, activerecord.errors.models.account.attributes.roles.invalid def create @account = Account.new(params[:account]) # we don''t need @user since it''s in params[:account] @role = @account.roles.build @role.role = "owner" end> Should that not be self.type (apart from the fact that type is not a > good name)? But if you want a default value for a column why not just > set the default in the database?It should, I made the changes in the middle of typing my question. I can add a default value to the db. But I want the be able to set the value depending on content: when a user registers with a new account; when an existing user adds a moderator to his account, etc... On Tuesday, May 1, 2012 4:28:31 PM UTC-4, Colin Law wrote:> > On 1 May 2012 17:05, Mohamad El-Husseini <husseini.mel-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > I have User, Account, and Role models. The Account model accepts nested > > properties for users. This way users can create their account and user > > records at the same time. > > > > class AccountsController < ApplicationController > > def new > > @account = Account.new > > @user = @account.users.build > > end > > end > > > > The above will work, but the user.roles.type defaults to member. At the > time > > of registration, I needuser.roles.type to default to admin. This does > not > > work: > > > > class AccountsController < ApplicationController > > def new > > @account = Account.new > > @role = @account.role.build > > # Role.type is protected; assign manually > > @role.type = "admin" > > @user = @account.users.build > > end > > end > > It depends what you mean by ''work''. It will assign the type of @role > to "admin" but the problem is that you have not saved it to the > database after changing the type. By the way, I advise against using > type as an attribute name, that is a reserved attribute name for use > with STI. > > > ... > > > # user_id, account_id, type [admin|moderator|member] > > class Role < ActiveRecord::Base > > belongs_to :user > > belongs_to :account > > after_initialize :init > > > > ROLES = %w[owner admin moderator member] > > > > private > > def init > > self.role = "member" if self.new_record? > > end > > end > > Should that not be self.type (apart from the fact that type is not a > good name)? But if you want a default value for a column why not just > set the default in the database? > > Colin >-- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To view this discussion on the web visit https://groups.google.com/d/msg/rubyonrails-talk/-/roLxK-sVUhgJ. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Colin Law
2012-May-02 06:35 UTC
Re: Setting an addional attribute on the join model in a has_many through relationship
On 1 May 2012 22:53, Mohamad El-Husseini <husseini.mel-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:>> It depends what you mean by ''work''. It will assign the type of @role >> to "admin" but the problem is that you have not saved it to the >> database after changing the type.You have not responded to the point above>> By the way, I advise against using >> type as an attribute name, that is a reserved attribute name for use >> with STI. > > I did change type to role. I get this rather mysterious error: Roles en-US, > activerecord.errors.models.account.attributes.roles.invalidCome back with more detail on this problem if it still exists. Post the full error message and show which line of code it relates to. Colin> > def create > @account = Account.new(params[:account]) # we don''t need @user since > it''s in params[:account] > @role = @account.roles.build > @role.role = "owner" > end > >> Should that not be self.type (apart from the fact that type is not a >> good name)? But if you want a default value for a column why not just >> set the default in the database? > > It should, I made the changes in the middle of typing my question. I can add > a default value to the db. But I want the be able to set the value depending > on content: when a user registers with a new account; when an existing user > adds a moderator to his account, etc... > > On Tuesday, May 1, 2012 4:28:31 PM UTC-4, Colin Law wrote: >> >> On 1 May 2012 17:05, Mohamad El-Husseini <husseini.mel-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: >> > I have User, Account, and Role models. The Account model accepts nested >> > properties for users. This way users can create their account and user >> > records at the same time. >> > >> > class AccountsController < ApplicationController >> > def new >> > @account = Account.new >> > @user = @account.users.build >> > end >> > end >> > >> > The above will work, but the user.roles.type defaults to member. At the >> > time >> > of registration, I needuser.roles.type to default to admin. This does >> > not >> > work: >> > >> > class AccountsController < ApplicationController >> > def new >> > @account = Account.new >> > @role = @account.role.build >> > # Role.type is protected; assign manually >> > @role.type = "admin" >> > @user = @account.users.build >> > end >> > end >> >> It depends what you mean by ''work''. It will assign the type of @role >> to "admin" but the problem is that you have not saved it to the >> database after changing the type. By the way, I advise against using >> type as an attribute name, that is a reserved attribute name for use >> with STI. >> >> > ... >> >> > # user_id, account_id, type [admin|moderator|member] >> > class Role < ActiveRecord::Base >> > belongs_to :user >> > belongs_to :account >> > after_initialize :init >> > >> > ROLES = %w[owner admin moderator member] >> > >> > private >> > def init >> > self.role = "member" if self.new_record? >> > end >> > end >> >> Should that not be self.type (apart from the fact that type is not a >> good name)? But if you want a default value for a column why not just >> set the default in the database? >> >> Colin > > -- > You received this message because you are subscribed to the Google Groups > "Ruby on Rails: Talk" group. > To view this discussion on the web visit > https://groups.google.com/d/msg/rubyonrails-talk/-/roLxK-sVUhgJ. > > To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org > To unsubscribe from this group, send email to > rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org > For more options, visit this group at > http://groups.google.com/group/rubyonrails-talk?hl=en.-- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Mohamad El-Husseini
2012-May-04 13:54 UTC
Re: Setting an addional attribute on the join model in a has_many through relationship
On Wednesday, May 2, 2012 2:35:02 AM UTC-4, Colin Law wrote:> > On 1 May 2012 22:53, Mohamad El-Husseini <husseini.mel-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > >> It depends what you mean by ''work''. It will assign the type of @role > >> to "admin" but the problem is that you have not saved it to the > >> database after changing the type. > > You have not responded to the point above >After another day wasted, I figured out what is happening, but not why. I was misled by the false impression that Rails always saved the joiner model automatically. This is not the case. With this following code snippet Rails automatically creates the Role (joiner) record. But the snippet below it Rails does not. And although I don''t know why, this is how Rails works. def new @account = Account.new(params[:account]) @user = @account.users.build end def new @account = Account.new(params[:account]) @account.save end This here *does not* save the Role record: (Interestingly, replace current_user.accounts.build with current_user.accounts.create and Rails will save the Role record) def new @account = current_user.accounts.build end def create @account = current_user.accounts.build(params[:account]) @account.save end It''s not a validation issue either. I created a blank application to test this and the results were consistent.>> By the way, I advise against using > >> type as an attribute name, that is a reserved attribute name for use > >> with STI. > > > > I did change type to role. I get this rather mysterious error: Roles > en-US, > > activerecord.errors.models.account.attributes.roles.invalid > > Come back with more detail on this problem if it still exists. Post > the full error message and show which line of code it relates to. > > Colin > > > > > def create > > @account = Account.new(params[:account]) # we don''t need @user > since > > it''s in params[:account] > > @role = @account.roles.build > > @role.role = "owner" > > end > > > >> Should that not be self.type (apart from the fact that type is not a > >> good name)? But if you want a default value for a column why not just > >> set the default in the database? > > > > It should, I made the changes in the middle of typing my question. I can > add > > a default value to the db. But I want the be able to set the value > depending > > on content: when a user registers with a new account; when an existing > user > > adds a moderator to his account, etc... > > > > On Tuesday, May 1, 2012 4:28:31 PM UTC-4, Colin Law wrote: > >> > >> On 1 May 2012 17:05, Mohamad El-Husseini <husseini.mel-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > wrote: > >> > I have User, Account, and Role models. The Account model accepts > nested > >> > properties for users. This way users can create their account and > user > >> > records at the same time. > >> > > >> > class AccountsController < ApplicationController > >> > def new > >> > @account = Account.new > >> > @user = @account.users.build > >> > end > >> > end > >> > > >> > The above will work, but the user.roles.type defaults to member. At > the > >> > time > >> > of registration, I needuser.roles.type to default to admin. This does > >> > not > >> > work: > >> > > >> > class AccountsController < ApplicationController > >> > def new > >> > @account = Account.new > >> > @role = @account.role.build > >> > # Role.type is protected; assign manually > >> > @role.type = "admin" > >> > @user = @account.users.build > >> > end > >> > end > >> > >> It depends what you mean by ''work''. It will assign the type of @role > >> to "admin" but the problem is that you have not saved it to the > >> database after changing the type. By the way, I advise against using > >> type as an attribute name, that is a reserved attribute name for use > >> with STI. > >> > >> > ... > >> > >> > # user_id, account_id, type [admin|moderator|member] > >> > class Role < ActiveRecord::Base > >> > belongs_to :user > >> > belongs_to :account > >> > after_initialize :init > >> > > >> > ROLES = %w[owner admin moderator member] > >> > > >> > private > >> > def init > >> > self.role = "member" if self.new_record? > >> > end > >> > end > >> > >> Should that not be self.type (apart from the fact that type is not a > >> good name)? But if you want a default value for a column why not just > >> set the default in the database? > >> > >> Colin > > > > -- > > You received this message because you are subscribed to the Google > Groups > > "Ruby on Rails: Talk" group. > > To view this discussion on the web visit > > https://groups.google.com/d/msg/rubyonrails-talk/-/roLxK-sVUhgJ. > > > > To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org > > To unsubscribe from this group, send email to > > rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org > > For more options, visit this group at > > http://groups.google.com/group/rubyonrails-talk?hl=en. >-- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To view this discussion on the web visit https://groups.google.com/d/msg/rubyonrails-talk/-/cQTXcjokzI8J. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.