Delete Rails model and its associations in one action? NEWBIE question - ruby-on-rails

I have a really simple association with the Devise user object where each user has one Profile (with more application specific stuff...) I am having no issues creating the User object and accessing the user and its profile object. i.e.,
#user.profile
However, I'm having an issues when I try to delete the profile object - I'd assume that when I delete the User object, it would also delete each associated object. The association in my User object is like so
accepts_nested_attributes_for :profile, :allow_destroy => true
The has_one and belongs_to associations are set on both the User and Profile objects. Maybe the issues is in Devise code - I'm stumped. An idea what I'm missing here.

You need to specify :dependent on the association:
has_one :profile, :dependent => :destroy
Look Association for more information.

Related

Rails Automatically create 1:1 dependency

I have a Rails 4 app that uses Devise.
I'm trying to let the User model alone so that I don't cross paths with Devise, so I created a Profile model for all my settings/views the user will have.
The Profile has
belongs_to :user
The User has
has_one :profile
Where do I put the logic that the app needs to know to create a profile upon new user creation, and delete it upon user deletion?
You can use Active Record Callbacks to create a profile. And you can use dependent: :destroy to make sure the profile will get destroyed when the user is destroyed.
In your models/user.rb
class User < ActiveRecord::Base
has_one :profile, dependent: :destroy # destroy user's profile
after_create :create_default_profile
... ...
private
def create_default_profile
Profile.create(user_id: self.id)
end
end
Rails associations have a dependent option, which handles deleting associated records.
User < ActiveRecord::Base
has_one :profile, dependant: :destroy
end
:destroy, when the object is destroyed, destroy will be called on its
associated objects.
:delete, when the object is destroyed, all its
associated objects will be deleted directly from the database without
calling their destroy method.
Creating the associated Profile can be done with ActiveRecord callbacks or in the controller. I have getting more and more weary of callbacks since its difficult to control when and where they are actually run.
In the case of Devise you would override the Devise::RegistrationsController.

Creating User Profiles

Pretty new to rails, and coding in general. I'm working on my own app right now, in which I'm trying to create user profiles. I know that there have been a few questions about this, but what I'm specifically trying to do is...
Upon authentication (which I've set up using Devise), the user is redirected to his/her profile page where he/she can set up their own profile, with fields similar to what you may find on a social networking website.
I'm running rails 4.1 and ruby 2.1 right now. Does anyone have any suggestions on the best way to go about doing this. As I mentioned I'm fairly new to rails, and have spent the last few days furiously searching for advice on the internet.
Does anyone know of a step by step guide?
I suppose what I need is just guidance on where to start.
Thanks!
You can add other fields like first name, last name, and date of birth to user table itself if you have minimum number of attributes you want to add. You can get all the details from current_user. But if you have many fields that you want to add to user profile then you can create a new model name UserProfile and add other related fields to this model. And add a one-to-one relationship between User and UserProfile table. So in the future if you want to add another relation/attribute with/to user, you can add it with UserProfile. That will reduce making a mess in your database in later stages.
recently i created user profile so that user can add/edit his personal details,see what he has uploaded.what he has liked,posted and edit/delete/update anything that he has created/uploaded.So in user profile all you need is to fetch all details/associated models of that user and show.So as u already have devise..you can get current_user and use user.rb model to understand all associations of user and get the data using associations ans display it on profile page
i have created a profile_controller
so in my nav_bar i have a link_to <% link_to "View Profile",show_profile_path(current_user) %>
where user is directed to profiles controller and i show the details without creating a new model(user has_one :profile)
i have a dedicated page to show profile details + a small page to show any user profile when hovered on users image
take a look here for view side idea... user profile page on bootstrap 3
=======updated part===========
suppose i have a user.rb(using devise)
###different associations of user can be:=
##this user can like/dislike any model having acts_as_votable
acts_as_voter
##user can tags post/audio/videos/images
acts_as_tagger
##my user can create post,pages,upload images/videos/songs/locations etc...
has_many :posts, :class_name => 'Post', :dependent => :destroy
has_many :pages, :class_name => 'Page', :dependent => :destroy
has_many :images, :class_name => 'Image', :dependent => :destroy
has_many :videos, :class_name => 'Video', :dependent => :destroy
has_many :audios, :class_name => 'Audio', :dependent => :destroy
has_many :places, :class_name => 'Place', :dependent => :destroy
has_many :profile_pictures, :class_name => 'ProfilePicture', :dependent => :destroy
#####so..as now i know that **my user can have post/pages/audios/videos** etc...i can also get the details about those associations(assuming you have configured belongs_to in associated models as well + tables with foreign_key as user_id in eash associtated table),such as:-*
##to get all videos that user has uploaded
#user.videos
##same applies for other associated models as well
#user.images..#user.audios...#user.pages.....#user.post....#user.places...#user.profile_pictures...etc
####So now you have all user(current_user data)...
###its time to show data in profiles_controller..
##your show method
## profile#show
def show
#user=User.find current_user.id
#all_user_videos=#user.videos..and so on
##get all user videos/images..etc and show it in your view file
##your view file can be the one that i shared the link or any other way that you want...
###there are lot of ways...google around and then you can get an idea as how to display user_profile page..as now you have the data(*Yipee*)
end##method ends
hope this helps

Accepts nested attributes convention for mongoid

I'm trying to create a form with nested attributes using mongoid. My models have the following code:
def Company
field :name
has_many :users, autosave: true, dependent: :destroy
accepts_nested_attributes_for :users
end
def User
belongs_to :company
has_one :profile
end
def Profile
belongs_to :user
end
The params that are returned from the form are in the following order:
"company"=>
{"users_attributes"=>
{"0"=>
{"profile_attributes"=>
{"first_name"=>"123123abcd123", "last_name"=>"abcd123123123"},
"email"=>"abcd#abcd.com123123123",
"password"=>"123123123123",
"password_confirmation"=>"123123123123"}},
"name"=>"abcd123123123",
"subdomain"=>"abcd123123123"}
Calling Company.create(params[:company]) seems to work, however it is not properly creating the user object. When I do company.users I can see that object, BUT when I do User.find, that document is not available. Reading the documentations I realized that the params should be passed in the following way:
"company"=>
{"users_attributes"=>
[{"profile_attributes"=>
{"first_name"=>"123123123", "last_name"=>"123123123"},
"email"=>"testin321#gmail.com",
"password"=>"123123",
"password_confirmation"=>"123123"}],
"name"=>"abcd123123123",
"subdomain"=>"abcd123123123"}
Note the subtle difference of using an array for users_attributes instead of a hash. This works right, but then it doesn't seem quite out of the box like it is with Active Record (and how it should be in something like in rails). I don't want to take the params hash and modify the data to make it follow certain conventions. Is there a better way, am I missing something?
if you can name the inputs as user_attributes[] that would make the array.
So instead of having user_attributes[0][profile_attributes] (I think you have something like this)
Make it to have user_attributes[][profile_attributes]
Could you post the code for the form? Then we can work on getting down to the reason it's formatted a certain way. (This should be a comment, but I am will to provide an answer once there are more details regarding the question.)
On a side note from your issue with the form in the view. I notice you are trying to create a company and it's nested users and the user and it's nested profile attributes as well. If you expect user to accept nested attributes for profile than you need to put that in the User model.
def User
belongs_to :company
has_one :profile, dependent: destroy, autosave: true
accepts_nested_attributes_for :profile
end
That may solve your problem, the error might arise from the User trying to mass-assign profile attributes without explicit instructions to do so.

Self reference in Mongoid is not working in both directions

I have a class like:
class User
include Mongoid::Document
has_and_belongs_to_many :following, class_name: "User", inverse_of: :followers
has_and_belongs_to_many :followers, class_name: "User", inverse_of: :following
When I add a user as following another user like this:
def follow id
self.following.push User.find(id)
end
following gets updated, but the "followers" reference does not for the User that is now being followed. I'm assuming I don't have to manually push to create the inverse relationship, so what am I doing wrong?
Are you using devise by any chance? If so, you may have problems with saving the inverse user because it is missing password combination. The other user, that is, the user adding the following user is probably already authenticated and is saving fine. I discovered this problem in a similar situation myself.
I've asked another question on how to disable validation on inverse objects:
Mongoid: disabling validation on inverse objects when saving parent for HABTM relationship Options

Creating many related models before_save

I have a User model with devise, a Team model, a Player model and a Trainer model. I want that when the User signs up, its associated team is created along with the associated trainer and players. I have set up the models as below:
user.rb
has_one :team
has_one :trainer, :through => :team
has_many :players, :through => :team
accepts_nested_attributes_for :team, :allow_destroy => true
before_save :create_team
def create_team
#team = Team.new(params[:team])
#team.user = self
#team.save
end
team.rb
belongs_to :user
has_one :trainer
has_many :players
accepts_nested_attributes_for :trainer, :allow_destroy => true
accepts_nested_attributes_for :player, :allow_destroy => true
trainer.rb and player.rb
belongs_to :team
I have not added the create_trainer and create_player functions, since I want the user to select them later in the game. So they should be empty during the creation of the user.
But the sign up process gives the following error:
No association found for name `trainer'. Has it been defined yet?
and refers to the line:
accepts_nested_attributes_for :trainer, :allow_destroy => true
in team.rb. What is wrong with having the Trainer item not defined yet, if there is no validation of presence of Trainer defined in the Team model? I tried adding some lines to the Trainer model, to set the attributes to default values like:
morale.default => (5..12).to_a.sample
but it gave further errors, so is probably wrong. Any comment is greatly appreciated, especially anything criticising the basis of tinking here, since I am a noob.
A few things:
Dont use instance variables in your model. To access the team in the user model, just do team or self.team.
Don't use before_save since you don't want to create the team each time you save your user.
Your create_team method should be:
after_create :my_create_team
def my_create_team
create_team #create an empty team
end
But if the data for the new team is already present in the form when the user signs up, then the team should automatically be created since you have accepts_nested_attributes_for :team.
I'm going to answer some of your questions in the comments here:
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_one
So when you add has_one :team you have now access to all these methods (build_team, create_team, team= etc)
By "empty", I just meant that if you just call create_team without any attributes, it would create a "default" team: no name etc. But it would be linked to your user though.
If you wanted to just create an "empty" team, you could just do this I think:
after_create :create_team
Creating your own method would just allow you to pass default parameters.
But you have probably added validation to the team, like validating the presence of its name.
Anyways, since you have accepts_nested_attributes_for :team, :allow_destroy => true, it should create the team automatically if you have the required fields for the user's team in the sign up form.

Resources