Rails connect the table task

Part of my RoR application is responsible for managing the portfolio of website projects. One website can have many images associated with it. One image can only be associated with one structure. I am using has_many with: through parameter to connect images with designs through a join table. And when the image is deleted, the associated entry in the connection table must be deleted. So I have the following models For images:

class  Image < ActiveRecord::Base
  has_one :images_site_designs , :class_name => "ImagesSiteDesigns" , :dependent => :destroy
  has_one :site_design , :through => :images_site_designs
end

      

For site_designs:

class SiteDesign < ActiveRecord::Base
  belongs_to :client
  has_many :images_site_designs , :class_name => "ImagesSiteDesigns"
  has_many :images , :through => :images_site_designs
end

      

And join the images_site_designs table:

class ImagesSiteDesigns < ActiveRecord::Base
  belongs_to :image 
  belongs_to :site_design
end

      

Generating new images for site_designs is fine, so the following code works fine:

   @site_design = SiteDesign.find(params[:id])
   @site_design.images << Image.new(params[:image])

      

But when I try to delete the image the following error appears:

 ActiveRecord::StatementInvalid in ImagesController#destroy

Mysql::Error: Unknown column 'id' in 'where clause': DELETE FROM `images_site_designs` WHERE `id` = NULL

      

It seems that rails are using the wrong column name to query the join_designs table images_site_designs. How can I fix this?

UPD:

image_controller which removes the image:

  def destroy
    @image = Image.find(params[:id])
    @image.destroy

    respond_to do |format|
      format.html { redirect_to(images_url) }
      format.xml  { head :ok }
    end
  end

      

Migration:

class CreateImages < ActiveRecord::Migration
  def self.up
    create_table :images do |t|
      t.string :url
      t.string :name
      t.text :description

      t.timestamps
    end
  end

  def self.down
    drop_table :images
  end
end
class CreateSiteDesigns < ActiveRecord::Migration
  def self.up
    create_table :site_designs do |t|
      t.string :name
      t.text :concept
      t.text :description
      t.integer :client_id

      t.timestamps
    end
  end

  def self.down
    drop_table :site_designs
  end
end

class CreateImagesSiteDesigns < ActiveRecord::Migration
  def self.up
    create_table :images_site_designs , :id => false do |t|
      t.integer :image_id
      t.integer :site_design_id
    end
  end

  def self.down
    drop_table :images_site_designs
  end
end

      

+2


source to share


3 answers


It is impossible to answer your question because it is not shown which code is causing the error. Presumably a call to destroy on an image instance, but can't be sure.

However, you don't seem to need this join model. The requirement seems to be met like this:



class SiteDesign < ActiveRecord::Base
  belongs_to :client
  has_many :images
end

class Image < ActiveRecord::Base
  belongs_to :site_design
end

      

Of course this would require a transfer (drag and drop the join table and add site_design_id to the image table), but this seems to be a cleaner solution. Any reason not to do this?

+1


source


The problem is that you have a migration that makes your image_site_design NOT a sample (no id column), but you then create an ActiveRecord model for it. In order for this to work, you need to have an ID column in the join table.



+2


source


If you want one image to be associated with only one design, why then are you using the has_and_belongs_to relationship (you are using an n: m table!)

I would refactor the following:

1) Transfer the model of your images and add the Site_design_id attribute

class CreateImages < ActiveRecord::Migration
  def self.up
    create_table :images do |t|
      t.string :url
      t.string :name
      t.text :description
      t.integer :site_design_id

      t.timestamps
    end
  end

  def self.down
    drop_table :images
  end
end

      

2) Drop ImagesSiteDesigns-Migration

drop_table :images_site_designs

      

3) Change the models to:

class SiteDesign < ActiveRecord::Base
  belongs_to :client
  has_many :images
end

class  Image < ActiveRecord::Base
  belongs_to :site_design
end

      

So you get a 1: n relationship and this should be the best solution for your specification.

You can use your models like this:

Image.first.site_design
=> <SiteDesign #id:...>
SiteDesign.first.image
=> <Image #id...>

SiteDesign.image = Image.new(params[:image])
...

      

0


source







All Articles