I have a user and profile models and I use the same form to populate them.
In my controller I have the line:
#user.build_profile
I would like to know what does this line do. The relationship between user and profile is one-to-one, and profile belong to user.
I also have a new model called image, I would like to set up a one-to-many relationship with user, using nested attributes. In my new action in the user coltroller, should I use a similar line like the one above?
#user.build_image
The complete new action:
def new
#user = User.new
#user.build_profile
respond_to do |format|
format.html # new.html.erb
format.json { render json: #user }
end
end
build_profile will create an empty profile object(which will belong to #user). Later on in the create action you will call
#user.save
which will save the profile (along with the user) into the database.
http://guides.rubyonrails.org/association_basics.html
-explains it
edit: For a has_many relation you would call
#user.images.build
to create a new image model. This rail cast goes over it
http://railscasts.com/episodes/196-nested-model-form-part-1
Related
So i'm having this issue trying to figure out how to use the build method in rails to create an object once a user completely registers and still have that object connected to the users id. I'm using devise for authentication and the model that needs to be created is called "app".
This is the create method for "app".
def create
#app = App.new(app_params)
#app.id = current_user.id
respond_to do |format|
if #app.save
format.html { redirect_to #app, notice: 'Application successfully created.'}
else
format.html { render action: 'new' }
end
end
end
Im getting this error:
Couldn't find App with id=1
from my multi step form controller:
def show
#user = User.find(current_user)
case step
when :school, :grades, :extra_activity, :paragraph, :submit
#app = App.find(current_user)
end
render_wizard
end
You need an after_create callback in the User model. It makes no sense to mess with the AppController because no forms have been filled up for the app and you have no app_params.
class User < ActiveRecord::Base
after_create :build_initial_app
protected
def build_initial_app
self.create_app
end
end
You can read more about this at the Rails Guides page for ActiveRecord Callbacks.
The problem line in your code is here:
#app.id = current_user.id
Setting an ActiveRecord object's id is a no-no. Think of the id attribute like you would a pointer in C. The system creates it for you, and you can use it to refer to a unique model object.
What you probably want is something along the lines of:
#app.user_id = current_user.id
Or, even better:
#app.user = current_user
To do that, you need to set up an association between your App model and your User model. There's a good tutorial on that here.
A newbie question regarding the ActiveRecord's save method.
If i have this code (as in rails guide):
def create
#post = Post.new(params[:post])
if #post.save
redirect_to #post
else
.....
end
end
The save method returns the new created Post object? How, after the code #post.save, rails know how to substitute the redirect_to #post with the proper post_id (1 or 2 or 3 or ....) to build the link?
It's an OOP concept.
So, after create, the #post is updated with the id, and everything just works.
Take a look at this code.
Hope it helps.
I'm going to explain it by presenting another piece of code that should make things easy to understand
def create
#user = User.new(params[:user])
if #user.save
redirect_to #user
Now :user contains the following information based on the User model: id, name, email, telephone.
So that means we have actually assigned to #user the above hashes.
The redirect_to will retrieve the hashes that is already stored in #user and display the new profile page.
I hope it helped.
I have 2 models - User model and Profile model. I have setup the relationship as follows:
class User
has_one :profile
end
class Profile
belongs_to :user
end
I have a profiles controller with 4 actions - new create edit and update. Once the User signs up or logs in he is redirected to the New action in the Profiles controller. From here how do I create a profile for that user? Specifically what should I have in my New action and Create action. Right now the route for the new action is just profiles/new which doesn't capture the Users params. I am trying to do this but its failing.
Profiles Controller
def new
#user = User.find(params[:id])
#profile = #user.build_profile
end
def create
#profile = current_user.build_profile(params[:profile])
if #profile.save
redirect_to current_user
else
render new
end
end
the new action in the profile controller doesn't need to get the id of the user from the params.
So your controller would be like this
def new
#user = current_user
#profile = #user.build_profile
end
def create
#profile = current_user.build_profile(params[:profile])
if #profile.save
redirect_to current_user
else
render new
end
end
actually sending the id of the user to the new action could be a security hole as I could send the id of another user and create a profile for some other user in the system, which shouldn't be allowed.
You should not be using User.find(params[:id] in your new action.
Just like in your create action below, you should be getting the User through current_user.
Is there more to the problem than not being able to properly fetch the User?
I have two forms in my new view, one is for the product and the other is for fotos.
When I upload the fotos with a select.file field, these are created by Ajax call by a file create.js.erb then when I fill the others fields to the product I've another button to create it. So I have two forms and one way to create each one.
The problem is the ID, the solution that I've found was to create an object before the user enter to the new view, so I have this code:
Product's controller:
def new
#product = current_user.products.create
end
It creates an object nil, now I can create my Foto to that object, like this:
Painting's controller:
def create
#product = Product.last
#painting = #product.paintings.create(params[:painting])
end
The problem is the line "#product = Product.last", I know that it isn't the right solution, because when I try the edit action, and when I try to create new objects it goes to the last product and not to the actual edit product.
How can I find that current product at my new action???
Thanks a lot.
Building a new object (really showing the new form, since #new is a GET request and should not make destructive changes)
def new
#product = current_user.products.build
end
Creating a new object
def create
#product = current_user.products.build(params[:product])
if #product.save
redirect_to #product
else
render :new
end
end
Showing the Edit form for an object
def edit
#product = current_user.products.find(params[:id])
end
Updating an existing product
def update
#product = current_user.products.find(params[:id])
if #product.update_attributes(params[:product])
redirect_to #product
else
render :edit
end
end
You'll notice that the GET requests (new and edit) make no chagnes to the database.
The two destructive requests (PUT and POST) to (update/create) make changes to the database.
What you are doing in general is awkward and probably not the best way to use the new action of a controller.
To answer your question you would need to pass in the ID of the product in your parameters.
Depending how you are submitting your paintings form you need to add the parameter in either the body of the request or the url. that way you would be able to do something like
Painting's controller
def create
#product = Product.find(params[:product_id]
#painting = #product.paintings.create(params[:painting])
end
If you add a code snippet of your views/forms I'll probably be able to help you better.
I have two models profiles and users on my form. After a user is created he can then move to editing his profile. The views work well. But when I click Save to update the editted profile. It doesn't update, but the flash notice displays that profile has been updated. What might be wrong? I'm not sure what went wrong. Below is the code.
class ProfilesController < ApplicationController
def new
##user.profile = Profile.new
#user = User.find(current_user.id)
#identity = #user.profile || #user.build_profile()
#identity.save
end
def update
#user = current_user
#identity = #user.profile
if #identity.update_attributes(params[:identity])
flash[:notice] = 'Profile was successfully updated.'
redirect_to(new_profile_path())
else
render :action => "new"
end
end
end
class UsersController < ApplicationController
def show
#user = current_user
#user = User.find(params[:id])
#identity = #user.profile || #user.build_profile()
#identity.save
end
......
end
Thanks for your assistance.
There are potentially a few things wrong here. But the best solution to this problem would be to simplify and use the built in rails features for editing associations.
What I suggest doing is using nested attributes, Ryan Daigle has a great article on them.
I'm not sure why you're calling save in a new action and not in a create, that doesn't feel right. Also check that the name of the model in the form you're submitting is identity and not user or profile.
Can a user exist without a profile?