Default values in join model

I have a has_many :through and I would like to take values from one
side and put them in the join model. Perhaps some code would be more
clear.

class Recipe < AR::Base
  has_many :fermentable_ingredients
  has_many :fermentables, :through => :fermentable_ingredients
end

class Fermentable < AR::Base
  has_many :fermentable_ingredients
  has_many :recipes, :through => :fermentable_ingredients
end

classFermentableIngredient < AR::Base
  belongs_to :recipe
  belongs_to :fermentable
end

Simple enough. When I assign a fermentable to a
fermentable_ingredienet, I would like to populate the
fermentable_ingredient with values in fermentable. Something like
this:

def fermentable=(f)
  self.potential = f.potential if potential.nil?
  self.color = f.color if color.nil?
  super
end

I know this doesn't work because the call to super fails.

Is there a clean way to do this?

Thanks,
--Dean
http://blog.brewsession.com/

Will this work?

class FermentableIngredient
  before_save :copy_from_fermentable

  protected
    def copy_from_fermentable
        if self.fermentable
          self.potential ||= fermentable.potential
          self.color ||= fermentable.color
        end
    end
end

Dan Manges

Thanks for the suggestion, but I want to do it before saving. Like
here:

class FermentableIngredientsController < ApplicationController
  def new
    @fermentable_ingredient = FermentableIngredient.new
    @fermentable_ingredient.fermentable =
Fermentable.find( params[:fermentable_id] )
    render
  end
end

That way the form fields for @fermentable_ingredient will be
automatically filled out. As it is I have to call an extra method
before render to transfer the values.

--Dean

Try this:

classFermentableIngredient < AR::Base
  belongs_to :recipe
  belongs_to :fermentable

  fermentable_with_copy=(f)
    self.potential ||= f.potential
    self.color ||= f.color
    fermentable_without_copy=f
  end
  alias_method :fermentable_without_copy=, :fermentable=
  alias_method :fermentable=, :fermentable_with_copy=
end

Dan Manges

Try this:

classFermentableIngredient < AR::Base
  belongs_to :recipe
  belongs_to :fermentable

  fermentable_with_copy=(f)
    self.potential ||= f.potential
    self.color ||= f.color
    fermentable_without_copy=f
  end
  alias_method :fermentable_without_copy=, :fermentable=
  alias_method :fermentable=, :fermentable_with_copy=
end

Dan Manges

That is *really* close, except it does not assign the fermentable to
the ingredient.

./script/console

i = FermentableIngredient.new

=> #<FermentableIngredient...>

i.fermentable = Fermentable.find(1)

=> #<Fermentable:... "potential"=>"1.037"}>

i.potential

=> 1.037

i.fermentable.potential

NoMethodError: You have a nil object when you didn't expect it!
The error occurred while evaluating nil.potential
        from (irb):5

i.fermentable

=> nil

Looks like this should work from the ruby-doc on alias_method
http://www.ruby-doc.org/core/classes/Module.html#M001706

  alias_method :orig_fermentable=, :fermentable=
  def fermentable=(f)
    self.potential ||= f.potential
    self.color ||= f.color
    orig_fermentable = f
  end

But it still does not assign the fermentable to the
fermentable_ingredient.

--Dean
http://blog.brewsession.com/

And the answer is:

  alias_method :orig_fermentable=, :fermentable=

  def fermentable=(f)
    self.potential ||= f.potential
    self.color ||= f.color
    self.orig_fermentable = f
  end

Thanks to Dan for the help

--Dean
http://blog.brewsession.com/