I have a form within my rails3.2 app for a Complaint, that also builds a new Company and Branch at the same time. That all works fine, but I want to store the id of the Company as the foreign key company_id in the Branch table.
This is my complaints controller:
def new
#complaint = Complaint.new
#complaint.build_company
#complaint.build_branch(:company_id => '#Trying to set the company ID here')
respond_to do |format|
format.html # new.html.erb
format.json { render json: #complaint }
end
end
What can I put after :company_id => to assign the id of the object created above?
Wouldn't it be just like this?
#complaint.build_branch(:company_id => #complaint.company_id)
The problem seems to be due to unsaved Company object & Complaint object. You have not outlined the details for the model, but I guess,
#complaint = Compplaint.create(#Whatever parameters are required)
company = #complaint.companies.create() #Assuming has_many relationship
#complaint.branches.create(:comapny_id => company.id)
create saves the record and generates the id, where as build and new does not.
You should also explore, has_many :through in your model.
The solution was to add the following code to the create action
def create
...
#complaint.branch.company = #complaint.company
#complaint.save
...
end
Related
I followed the guide in the wiki to use my models from my engine in my main-app with active admin.
The only thing I must change (that doesn't mentioned in the wiki) was this:
if defined?(ActiveAdmin)
ActiveAdmin.register Blog::Category do
end
end
I just added: Blog::.
In my engine "Blog" I added a model named "category" with a name:string attribute. But when I add one in active admin the field name wasn't saved in the database. My request parameters are:
{"utf8"=>"✓", "authenticity_token"=>"PzKDTcoJZ6Sy2tXgw9WSwXiR7aZp81lOtBvfD5Ec3F72H5L7MEMLjlOFgKWQBo2U4n9mPc7AgjcIS3MTIY2nZA==", "category"=>{"name"=>"asdasd"}, "commit"=>"Update Category", "id"=>"1"}
any ideas why it isn't saved in the databse?
When I create a new one, the record is created but without my input.
I ran into the same problem. I was able to get the resources to save properly by overriding the activeadmin controller actions (in e.g. app/admin/category.rb) like this
ActiveAdmin.register Blog::Category do
permit_params :the, :parameters, :for, :your, :resource
controller do
def create
#category = Blog::Category.new permitted_params[:category]
if #category.save
notice = 'Category was successfully created.'
redirect_to admin_blog_category_url(#category), notice: notice
else
render :new
end
end
end
end
I'm not sure exactly what's going on in the default case yet, but my guess is that the activeadmin controller action is not creating the object in the right namespace - that is, it does something like #category = Category.new rather than #category = Blog::Category.new. A similar override appears to be necessary for the :update action as well.
When a user creates a new booking record, part of the data entered is an email address. This email address is used to create a new guest record at the same time if they don't already exist. The booking should have the guest id as part of the record.
In my models I have defined the relationships so:
accommodations has_many bookings
guests has_many bookings
bookings belongs_to accommodations
bookings belongs_to guests
This is what I have so far in the create action of my BookingsController:
...
def create
accommodation = current_user.accommodation
#booking = accommodation.bookings.build(post_params)
#guest = accommodation.guests.build(params[:email])
if #booking.save
flash[:success] = 'The booking has been added successfully.'
redirect_to :controller => 'bookings', :action => 'index'
else
render 'new'
end
end
...
My questions are:
Should I use 'build' twice as I want the new booking to have the guest id?
How can I check if guest exists already using email?
Is it safe/secure to use params[:email] when building the guest?
If you're not using #guest in the view, there's no need for it to be an instance variable. So:
accommodation = current_user.accommodation
guest = Guest.find_or_create_by(:email => params[:email])
#booking = accommodation.bookings.new(post_params.merge(:guest_id => guest.id))
You don't need to use build in your #create method because its main use is to maintain association ties with objects that still don't have a primary key. But since you're persisting your stuff in here, we can go with good old new from Ruby.
Hi i was wondering if there was a way a user can update a review they have already written, i tried using cancan but ran into a few problems so i rather find out if there is an easier way. This is code from the 'new' method in the reviews controller
def new
if logged_in?
#review = Review.new(:film_id => params[:id], :name =>
User.find(session[:user_id]).name)
session[:return_to] = nil
else
session[:return_to] = request.url
redirect_to login_path, alert: "You must be logged in to write a review"
end
end
and the 'create' method
def create
# use the class method 'new' with the parameter 'review', populated
# with values from a form
#review = Review.new(params[:review])
# attempt to save to the database, the new review instance variable
if #review.save
# use the class method 'find' with the id of the product of the
# saved review and assign this product object to the variable 'product'
film = Film.find(#review.film.id)
# redirect the reviewer to the show page of the product they reviewed,
# using the product variable, and send a notice indicating the review
# was successfully added
redirect_to film, notice: "Your review was successfully added"
else
# if the review could not be saved, return / render the new form
render action: "new"
end
end
i want the user to edit their review if they have already written a review for a product. Instead of having two reviews from the same user for the same product.
You could potentially sub something like this into the create method:
# Assumes that your user names are unique
#review = Review.find_or_create_by_film_id_and_name(params[:review][:film_id], User.find(session[:user_id]).name)
#review.update_attributes(params[:review])
This does the following
Checks whether the user has created a review for the film
If yes, assigns the existing review to the #review instance variable
If not, creates a new Review object and assigns it to #review
Updates #review with params[:review]
Alternatively, the following statements will accomplish the same without using the Rails find_or_create convenience method:
user_name = User.find(session[:user_id]).name # To avoid two DB lookups below
#review = Review.find_by_film_id_and_name(params[:review][:film_id], user_name) || Review.new(:film_id => params[:review][:film_id], :name => user_name)
#review.update_attributes(params[:review])
To update a record, you should use the update action, which is requested after the user submitted the edit form.
Make your User model have has_many/has_one :reviews. And Review model belongs_to :user. And then if you have any kind of authorization(and you should have, for ex: devise) you'll know if user of review is currently logged user. If so then render edit button, otherwise not render.
Also according to CRUD conventions, there are 2 actions you need. First its edit and other one update. You can read about it on railsguides.com
Every company is supposed to have one CompanyContact. My Company form has fields for company contacts. When I update the Company and add a new company contact, it works fine, because in the show page for company, it does show the new company contact. But when I click the Edit link that takes me to the Edit page (note: I don't even click the update button yet), in the Edit Company form where the companycontact is supposed to be is blank. So i check the logs and the companycontact was deleted.
DELETE FROM "company_contacts" WHERE "company_contacts"."id" = ? [["id", 4]]
I'm confused because I haven't called any delete action.
----------------------------------------
company.rb
has_one :company_contact, :dependent => :destroy
accepts_nested_attributes_for :company_contact
----------------------------------------
company_contact.rb
belongs_to :company
----------------------------------------
companies_controller.rb
def new
#company = Company.new
company_contact = #company.build_company_contact
respond_to do |format|
format.html # new.html.erb
format.json { render json: #company }
end
end
def edit
#company = Company.find(params[:id])
company_contact = #company.build_company_contact
end
In your edit action you're building a company contact for your company, but your company has only one company contact. Check for existence before building a new one:
company_contact = #company.company_contact || #company.build_company_contact
I found this in the ActiveRecord source, which confirms the suspicion I commented on above (comments in the code below are mine):
class HasOneAssociation < SingularAssociation #:nodoc:
def replace(record, save = true)
raise_on_type_mismatch(record) if record
load_target
reflection.klass.transaction do
# !!!
# This is where your record is getting deleted
# !!!
if target && target != record
remove_target!(options[:dependent]) unless target.destroyed?
end
if record
set_owner_attributes(record)
set_inverse_instance(record)
if owner.persisted? && save && !record.save
nullify_owner_attributes(record)
set_owner_attributes(target) if target
raise RecordNotSaved, "Failed to save the new associated #{reflection.name}."
end
end
end
self.target = record
end
...
This replace method appears to be called whenever record.build_association is used.
Your edit action shouldn't build the associated record if one already exists.
I am having trouble passing parameters
My application that is setup like this:
Fact belongs_to Source
Source has_many Facts
Source is nested under User in routes
I am using the Facts form to create the Source data. So I have getter and setter methods in the Facts model like this:
def source_name
source.try(:name)
end
def source_name=(name)
self.source = source.find_or_create_by_name(name) if name.present?
end
This is working great, but it is not setting the user_id for the parent User attribute. As a result, sources are created, but they are not associated with the User.
I have a hidden field with user_id in the form, but the user_id is still being set. What is the easiest way to pass and save the user_id so the nested relationship is set?
Here is the create method for the Source controller:
def create
#user = User.find(params[:user_id])
#source = #user.source.build(params[:source])
...
end
I think the problem is that you are creating source directly from the setter method in the Fact model. Unless you establish the chain by using something like build in the FactController, the user_id will not be set. What you are doing in SourceController needs to be done in the FactsController too. Also, it seems that the ids are set only for the immediate parent when you use the build command. You can try something as below:
def create
#source = current_user.sources.find_or_create_by_name(params["source_name"])
#fact = #source.facts.build(:user_id => #source.user_id)
....
end
Hope that helps.
If your user has a single Source, try the following as your create() method:
def create
#user = User.find params[:user_id]
#user.source = Source.new params[:source]
if #user.save
redirect_to #user, :flash => { :success => "Source updated!" }
else
flash[:error] = "Failed to update the source!"
render :action => "new"
end
end
Creating the Source as an attribute on the User object and then saving the User object should automatically associate the Source with the User.