Rails how to make profile form accept a user model attribute? - ruby-on-rails

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

Update a rails parent record with information from the child record upon creation

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.

Using form_for for one-to-one relation model in rails

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)

Ruby on Rails - Need help associating models

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)

Devise: Associated Model on Sign Up: Can't mass-assign

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 %>

adding hobby to a user

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

Resources