I setup Devise on User model with its default options.
I also have a Company model that needs to add data added whenever a user registers. A company owner setups a User to login with and a Company profile, both in the same form.
I setup Company model with has_many :users and User with has_one :company, but I keep getting Can't mass-assign protected when submitting the form. I followed Profile model for Devise users? and others from Stackoverflow, but no luck.
How can I setup the User and Company model to add the necessary data whenever a user registers? User data to User and company data to Company.
You can use a callback to create a object Company after create a user, for example on your User.rb model add: (I don't know your company attributes but you can take a look to this example)
after_create :first_company
def first_company
company = self.company.new(:title => "Company title here", :created_at => Time.now #add more attributes if required)
board.save!
end
You must add attr_accessible to attributes that you receive from your action controller.
Add the next code on your models to remove the Can't mass-assign protected
attr_accessible :title #...more attributes if required
Regards!
How I got it working:
My User model has:
attr_accessible :company_attributes
belongs_to :company
accepts_nested_attributes_for :company
My Company model has:
has_many :users
And the new.html.erb from devise/registrations is with the following added:
<% resource.build_company %>
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
[ fields for User ]
<%= f.fields_for :company_attributes, resource.company do |company| %>
[ fields for Company ]
<% end %>
<% end %>
Related
I have a one-to-one models for user and profile.
The following is the code for the User model created by device.
class User < ActiveRecord::Base
has_one :profile , dependent: :destroy
end
Code for Profile model.
class Profile < ActiveRecord::Base
belongs_to :user
end
Now I have basic Profile for a User which was created at sign up. Now how do I go about editing user profile using the helper device provides current_user with form_for?
We did something like this:
#app/models/user.rb
Class Model < ActiveRecord::Base
before_create :build_profile
end
This populates the profile record in the database, allowing you to update it later on
Once you've saved the user, you will be best using accepts_nested_attributes_for to populate & save profile options through a form for the user, like this:
#config/routes.rb
resources :users do
resources :profiles
end
#app/views/profiles/edit.html.erb
<%= form_for #profile do |f| %>
<%= f.hidden_field :user_id, current_user.id %>
<%= f.text_field :your_profile_options %>
<% end %>
This is a very basic way to do it, but hopefully will give you more ideas. If you want to see this in the wild, check out http://video-conference-demo.herokuapp.com (it uses Devise to handle users & has extra "profile" model too)
I've read through many other topics here (1, 2, 3...) but none really solved my problem.
Here are my 3 models.
User
has_many :memberships
has_many :accounts, :through => :memberships
accepts_nested_attributes_for :memberships
end
Account
has_many :memberships
has_many :users, :through => :memberships
accepts_nested_attributes_for :memberships
end
Membership
attr_accessible :account_id, :url, :user_id
belongs_to :account
belongs_to :user
end
As you can see, my join model Membership has an additional attribute: :url.
In my Accounts table, I store names of online services, such as GitHub, Stack Overflow, Twitter, Facebook, LinkedIn.. I have 9 in total. It's a fixed amount of accounts that I don't tend to update very often.
In my User form, I'd like to create this:
The value entered in any of these field should be submitted in the Memberships table only, using 3 values:
url (the value entered in the text field)
user_id (the id of the current user form)
account_id (the id of the related account, e.g. LinkedIn is '5')
I have tried 3 options. They all work but only partially.
Option #1
<% for account in #accounts %>
<%= f.fields_for :memberships do |m| %>
<div class="field">
<%= m.label account.name %><br>
<%= m.text_field :url %>
</div>
<% end %>
<% end %>
I want to have 9 text field, one for each account. So I loop through my accounts, and create a url field related to my memberships model.
It shows my fields correctly on the first time, but the next time it'll display 81 fields:
Option #2
<% #accounts.each do |account| %>
<p>
<%= label_tag(account.name) %><br>
<%= text_field_tag("user[memberships_attributes][][url]") %>
<%= hidden_field_tag("user[memberships_attributes][][account_id]", account.id) %>
<%= hidden_field_tag("user[memberships_attributes][][user_id]", #user.id) %>
</p>
<% end %>
I'm trying to manually enter the 3 values in each column of my Memberships tables.
It works but :
displaying both account and user id's doesn't seem very secure (no?)
it will reset the fields everytime I edit my user
it will duplicate the values on each submit
Option #3 (best one yet)
<%= f.fields_for :memberships do |m| %>
<div class="field">
<%= m.label m.object.account.name %><br>
<%= m.text_field :url %>
</div>
<% end %>
I'm creating a nested form in my User form, for my Membership model.
It works almost perfectly:
exactly 9 fields, one for each account
no duplicates
But, it only works if my Memberships table is already populated! (Using Option #2 for example).
So I tried building some instances using the UsersController:
if (#user.memberships.empty?)
#user.memberships.build
end
But I still get this error for my m.label m.object.account.name line.
undefined method `name' for nil:NilClass
Anyway, I'm probably missing something here about has_many through models. I've managed to create has_and_belongs_to_many associations but here, I want to work on that join model (Membership), through the first model (User), using information about the third model (Account).
I'd appreciate your help. Thank you.
in the controller, fetch the list of memberships for a particular user
# controller
# no need to make this an instance variable since you're using fields_for in the view
# and we're building additional memberships later
memberships = #user.memberships
then loop through each account and build a membership if the user has no membership for an account yet.
# still in the controller
Account.find_each do |account|
unless memberships.detect { |m| m.account_id == account.id }
#user.memberships.build account_id: account.id
end
end
then in your view, you change nothing :)
I would use the following data-design approach. All users in your system should have the
memebership entries for all possible accounts. The active configurations will have a value for the url field.
User
has_many :memberships
has_many :accounts, :through => :memberships
has_many :active_accounts, :through => :memberships,
:source => :account, :conditions => "memberships.url IS NOT NULL"
accepts_nested_attributes_for :memberships
end
Now
curent_user.active_accounts # will return the accounts with configuration
curent_user.accounts # will return all possible accounts
Add a before_filter to initialize all the memberships that a user can have.
class UsersController
before_filter :initialize_memberships, :only => [:new, :edit]
private
def initialize_memberships
accounts = if #user.accounts.present?
Account.where("id NOT IN (?)", #user.account_ids)
else
Account.scoped
end
accounts.each do |account|
#user.memberships.build(:account_id => account.id)
end
end
end
In this scenario you need to initialize the memeberships before the new action and all the memberships should
be saved in the create action ( even the ones without url).
Your edit action doesn't need to perform any additional data massaging.
Note:
I am suggesting this approach as it makes the management of the form/data straight forward. It should only
be used if the number of Account's being associated is handful.
Ok, am still a newbie in ruby on rails trying to learn my way around. I have two models (User model and Comment model). Basically a user has a simple profile with an 'about me' section and a photo's section on the same page. Users must be signed in to comment on other users profiles.
My User Model
class User < ActiveRecord::Base
attr_accessible :email, :name, :username, :gender, :password, :password_confirmation
has_secure_password
has_many :comments
.
.
end
My Comment Model
class Comment < ActiveRecord::Base
belongs_to :user
attr_accessible :content
.
.
end
In my comments table, I have a user_id column that stores the id of the user whose profile has been commented on and a commenter_id column that stores the id of the user commenting on the profile.
Comment Form
<%= form_for([#user, #user.comments.build]) do |f| %>
<%= f.text_area :content, cols: "45", rows: "3", class: "btn-block comment-box" %>
<%= f.submit "Comment", class: "btn" %>
<% end %>
My comments Controller
class CommentsController < ApplicationController
def create
#user = User.find(params[:user_id])
#comment = #user.comments.build(params[:comment])
#comment.commenter_id = current_user.id
if #comment.save
.........
else
.........
end
end
end
This works fine storing both user_id and commenter_id in the database. My problem comes when displaying the user comments on the show page. I want to get the name of the user who commented on a specific profile.
In my user controller
def show
#user = User.find(params[:id])
#comments = #user.comments
end
I want to get the name of the user from the commenter_id but it keeps throwing errors undefined method 'commenter' for #<Comment:0x007f32b8c37430> when I try something like comment.commenter.name. However, comment.user.name works fine but it doesn't return what I want. Am guessing am not getting the associations right.
I need help getting the correct associations in the models so as to get the name from the commenter_id.
My last question, how do I catch errors in the comments form? Its not the usual form_for(#user) where you do like #user.errors.any?.
routes.rb
resources :users do
resources :comments, only: [:create, :destroy]
end
Try something like this in your models
class User < ActiveRecord::Base
has_many :received_comments, :class_name => "Comment", :foreign_key => "user_id"
has_many :given_comments, :class_name => "Comment", :foreign_key => "commenter_id"
end
class Comment < ActiveRecord::Base
belongs_to :user # comment about profile
belongs_to :commenter, :class_name => "User", :foreign_key => "commenter_id"
end
check out: http://guides.rubyonrails.org/association_basics.html
you can probably come up with better naming on the has_many collections, received and given were the best I could do on short notice :)
Note: foreign_key is option in many cases, left it in above - i think it helps with clarity
has_many fk refers to the the column in the many table (other table)
belongs_to fk refers to the column in the many table (this table)
I have a user profile form which a user fills out after the user record has been created in the users database (via a users model). In the profile form along with the profile fields I have an email field which is actually from the users table. Here is my setup:
class Profile < ActiveRecord::Base
belongs_to :user
accepts_nested_attributes_for :user
...
class User < ActiveRecord::Base
has_one :profile
...
In the profile form:
<%= form_for #profile do |f| %>
<%= f.fields_for :user do |l| %>
<%= l.text_field :email, :placeholder => "email address" %>
<% end %>
...
and in my profiles->new method, I have this..
profile.build_user
..now what happens is that a whole new user record is created when a profile is created. What I want is that when a profile is created, the email address should get updated in the users table for this user. Can someone spot the issue in my code? I suspect it's something to do with the last line of code i posted but not sure.
Thanks.
Check out the :accepts_nested_attributes_for method, I think this might be what you're looking for
http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html#method-i-accepts_nested_attributes_for
in the user model you could have accepts_nested_attributes_for :user_profile
I'm trying to write a rails application. I'm a ruby-on-rails newbie.
I have a User model and a Hobby model.
class User < ActiveRecord::Base
has_many :hobbies
end
class Hobby < ActiveRecord::Base
belongs_to :user
end
During the new user registration, I have used a text box where I enter a value for hobby. Then, when I press a button 'Add hobby', a method in UsersController add_hobby is to be called where I intend to append the value entered for hobby by user to the user i.e
#user.hobbies << hobby
However, my problem is that the user object has not been saved yet, so there is no way to access a particular user object. How do I get around this problem ?
You can build nested form as such in your templates:
<%= form_for #user do |user_form| %>
<%= user_form.text_field :name %>
<% for hobby in #user.hobbies %>
<%= user_form.fields_for hobby, :index => hobby do |hobby_form|%>
<%= hobby_form.text_field :name %>
<% end %>
<% end %>
<% end %>
Then add accepts_nested_attributes_for in your User model
class User < ActiveRecord::Base
has_many :hobbies
accepts_nested_attributes_for :hobbies, :allow_destroy => true
end
As per my understanding, Its better to save the hobbies after user has been created. Afterall its not logical to save user's hobbies even without having a user created.
If you are allowing multiple hobbies for a user, have a javascript array in client side. when user added a hobby add it to the javascript array and update the page. (You can do it with some DHTML / Javascript). When you are saving the user pass the hobby array and in the controller you can split and save the hobbies.
cheers
sameera