belongs_to

hi i have a belongs to set up between 2 models. Exhibition belongs to
license_instance. The model code is fine because i use it in a number of
other places on the site. One thing i would like to do is create the 2
models at the same time in one form. I have been usinghttp://railsforum.com/viewtopic.php?id=717but i am running in to
trouble when i try and save.

The folloing is my controller code

#####################################################
  def create
    #create the new @exhibition model
    @exhibition = Exhibition.new(params[:details])
    @exhibition.user = current_user
    @exhibition.listing_status = ListingStatus.find_by_id(2)
    @exhibition.image_id = -1

    #check if license needs to be created for this model.
    if @exhibition.description != ""
      @licenseinstance =
@exhibition.build_license_instance(params[:newdetails])
      @licenseinstance.format = "Text"
      @licenseinstance.license_jurisdiction_id = 1
    end

    #checks if the is free button has been ticked. if so sets this to
the price.
    if params[:otherdetails][:isfree] == "yes"
      @exhibition.admission_price = "Free"
    end

    #saves the whole exhibition with the license details included.
    if @exhibition.save
      flash[:notice] = "Exhibition details inserted"
      session[:exhibition] = @exhibition
      redirect_to :controller => "/listing/edit", :action => "index"
    else
      flash[:notice] = "Error inserting Exhibition and creating license"
      @license_types = LicenseType.find(:all)
    end
  end
#####################################################

everything works but the license instance does not get saved. What am i
doing wrong??? Do i have to call the .save method on the license object?
I was under the understanding that the .build_license_instance method
would do this when the .save method on the exhibition is called.

Where does the license_instance actually get connected with the
exhibition? What exactly is in the build_license_instance method?

Best,

-r

hi,

try
@licenseinstance =License.new(params[:newdetails])#perhaps this is the case for you
@exhibition.liscense_instance=@licenseinstance
then save
analogous to above code worked for me

regards

gaurav

Have a go at:

    @licenseinstance =License.new(params[:newdetails])

    if @licenseinstance.valid?
        @exhibition.license_instance=@licenseinstance
    else
      flash[:notice] = "License is not valid"
      redirect_to :action =>"somewhere" and return
    end

    if @exhibition.save
      flash[:notice] = "Saved!"
      redirect_to :action =>"somewhere" and return
    end

You might want to look at transactions
(http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html#M000585).
and validates_associated
(http://api.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html#M000820)

You'll probably also benefit from this:

http://i.nfectio.us/articles/2006/01/26/enhancing_rails_errors

which will allow you to consolidate the error_messages when both car & license_instance fail to validate.

Cheers,
Michael Johnston

This is the way Rails works.

belongs_to is not considered an "owning" type assosiation. Only the has_one & has_many will propagate save & delete to their child objects.

I also consider this a problem with Rails because there are many types of entity relationship where it is natural for the "owning" entity to have the foreign key, for example with an Address entity, where you want other entities to be able to use the Address entity (or even for one entity to have several addresses, but each is a separate to-one relationship, ie: business_address, billing_address, etc.)

Other ORMS I've used in the past have had the opposite restriction, where you ONLY had the ability to create a has_one association on the object that had the foreign key, and had to emulate other-object- foreign-key associations using has_many with code to restrict membership to 1.

In my opinion an ORM should be agnostic about which side of a to-one association is considered parent and which is considered child.

Here is some more discussion of this issue:

http://javathehutt.blogspot.com/2006/05/rails-realities-part-12- active-record.html
http://grahamglass.blogs.com/main/2005/11/my_ruby_on_rail_3.html

This has been discussed many times, and the solution is to use polymorphic associations. Although polymorphic associations are very useful, to my mind they are not the best way of modelling simple to_one relationships where the parent record holds the foreign key. And, as the javathehutt guy mentions, if you use polymorphic associations, you are going to need custom code to propagate saves anyway except when model objects are first created.

Since it has been discussed many times, it seems unlikely that this aspect of Rails will change.

Also, see http://javathehutt.blogspot.com/2006/07/rails-realities- part-14-rtfm-and-dont.html for a potential gotcha with propagating deletions.

Cheers,
Michael Johnston

hi,

I customized my errors method this way
and made it helper and had
validates_associated :model_name#whatever model in my model code

def errors_finder(object_name, options = {})
options = options.symbolize_keys

object = instance_variable_get("@#{object_name}")
if object && !object.errors.empty?
      content_tag("div",
         content_tag(
           options[:header_tag] || "h2",

           "#{pluralize(object.errors.count, "error")} prohibited this #{object_name.to_s.gsub("_", " ")} from being saved"
         ) +
         content_tag("p", "There were problems with the following fields:") +

         content_tag("ul", object.errors.full_messages.collect { |msg| content_tag("li", msg) })+
         content_tag("ul",relation_finder( object)

),
“id” => options[:id] || “errorExplanation”, “class” => options[:class] || “errorExplanation”

       )
     else
       ""

     end
   end

end

def relation_finder object_name
relation_error_collector=[]
object_name.class.column_names.select{|v| v=~ /[a-z]_id/}.each do |l|

 rel=l.gsub("_id","")
 obj=object_name.send(rel)
 if obj != nil
   relation_error_collector<<obj.errors.full_messages.collect { |msg| content_tag("li", msg) }

 end

end
relation_error_collector
end

hope this helps…

regards
gaurav