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
Related
this is my first post so I'm not exactly sure how to format this. Lmk if I'm doing anything wrong.
I'm fairly new to rails and I am making an app that basically just allows users to submit 'grimes' (which you can think of as reviews) for other users. The app has two basic models: users and grimes.
User Model:
class User < ApplicationRecord
has_many :grimes
end
Grimes Model:
class Grime < ApplicationRecord
belongs_to :user
validates :user, presence: true
end
each grime has a griminess attribute, which is basically the rating from 1-5 for the grime. Each user also has a griminess attribute, which I would like to be the sum of the griminess of each of a user's associated grimes. ie. if user1 has two grimes, g1 with griminess 3 and g2 with griminess 2, then user1 griminess should be 5.
I could do this by iterating through each of the user's grimes when I would like to display the user's griminess, but that seems very unnecessary. Instead, I would like to just increment the user's griminess each time a new grime associated with them is added, but I can't figure out how to do that right now.
the form to create a grime looks like this:
<%= form_for #grime do |f| %>
Title: <%= f.text_field :title %><br />
Description: <%= f.text_area :description %><br />
Griminess Level: <%= f.select :griminess, (0..5) %>
Select Grimer: <%= f.collection_select(:user_id, User.all, :id, :name) %><br />
<%= f.submit %>
<% end %>
and my grimes#create looks like this:
def create
#grime = Grime.new(grime_params)
if #grime.save
flash[:success] = "Grime Saved Successfully"
redirect_to #grime
else
flash[:error] = "Error: Could Not Save Grime!"
render :new
end
end
I feel like I should be able to do something like #grime.user.griminess += #grime.griminess in the create method, but that doesn't seem to work for me. Can anyone recommend a better way to approach this?
Add after_save hook in Grime which will call a method on a grime whenever that grime is saved.
class Grime < ApplicationRecord
after_save :update_user_griminess # register the callback
belongs_to :user
validates :user, presence: true
#callback body
def update_user_griminess
user.griminess = user.grimes.sum(:griminess) # update user griminess as sum of it's all grimes' griminess
user.save
end
end
There is an alternative after_create hook in ActiveRecord which runs just once when the object is created for the first time, but I preferred after_save here to adjust for cases when a grime's griminess is updated.
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)
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 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 %>
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