Merlin Jackson
Merlin Jackson

Reputation: 142

Adding Tags in Rails

Adding Tags and I Get this ERROR:

SQLite3::SQLException: no such column: taggings.available_work_id: SELECT "tags".* FROM "tags" INNER JOIN "taggings" ON "tags"."id" = "taggings"."tag_id" WHERE "taggings"."available_work_id" = ?

Available_work.index.html

    <tbody>
    <% @available_works.each do |available_work| %>
      <tr>
        <td><%= available_work.title %></td>
        <td><%= available_work.description.html_safe %></td>
        <td>Tags: <%= raw available_work.tags.map(&:name).map { |t| link_to t, tag_path(t) }.join(', ') %></td>
        <td><%= image_tag available_work.image_url(:thumb) %></td>
        <td><%= link_to 'Show', available_work %></td>
        <td><%= link_to 'Edit', edit_available_work_path(available_work) %></td>
        <td><%= link_to 'Destroy', available_work, method: :delete, data: { confirm: 'Are you sure?' } %></td>
      </tr>
    <% end %>
    </tbody>
   </table>

Available_work.rb

 class AvailableWork < ActiveRecord::Base
    attr_accessor :image, :remote_image_url, :tag_list
    mount_uploader :image, ImageUploader
    has_many :taggings
    has_many :tags, through: :taggings


    def self.tagged_with(name)
      Tag.find_by_name!(name).available_work
    end

    def self.tag_counts
      Tag.select("tags.*, count(taggings.tag_id) as count").
        joins(:taggings).group("taggings.tag_id")
    end

    def tag_list
      tags.map(&:name).join(", ")
    end

    def tag_list=(names)
      self.tags = names.split(",").map do |n|
        Tag.where(name: n.strip).first_or_create!
      end
    end
    end

Tag.rb

 class Tag < ActiveRecord::Base
 has_many :taggings
 has_many :available_work, through: :taggings
 end

Taggings.rb

 class Tagging < ActiveRecord::Base
 belongs_to :tag
 belongs_to :availble_work
 end

Schema

create_table "available_works", force: :cascade do |t|
    t.string   "title"
    t.string   "description"
    t.string   "tags"
    t.string   "image"
    t.datetime "created_at",  null: false
    t.datetime "updated_at",  null: false
    t.string   "taggings"
    end

Upvotes: 2

Views: 1474

Answers (1)

max
max

Reputation: 102443

You would have to add an available_work_id column the to taggings table. It might be better however to create a polymorphic relation to the tagged object though so that you can use tags for more than the AvailableWork model.

EDITED. There where several mistakes in my example. Here is a complete running version:

class Tag < ActiveRecord::Base
  has_many :taggings

  def self.tag_counts
    select("tags.*, count(taggings.tag_id) as count")
      .joins(:taggings)
      .group("taggings.tag_id")
   end
end

class Tagging < ActiveRecord::Base
  belongs_to :tag
  belongs_to :tagged,
             polymorphic: :true,
             inverse_of: :taggings
end

class AvailableWork < ActiveRecord::Base
  has_many :taggings, as: :tagged
  has_many :tags, through: :taggings

  def self.tagged_with(name)
    # We have to do this in two queries since Rails does not
    # do joins on polymorphic relations.
    ids = Tagging.where(tagged_type: self.name)
           .joins(:tag)
           .where(tags: { name: name }).pluck(:tagged_id)
    find(ids)
  end

  def self.tag_counts
    Tag.tag_counts.where(taggings: { tagged_type: self.name  })
  end

  def tag_list
    tags.map(&:name).join(", ")
  end

  def tag_list=(names)
    self.tags = names.split(",").map do |n|
      Tag.where(name: n.strip).first_or_create!
    end
  end
end

ActiveRecord::Schema.define(version: 20150621234032) do
  create_table "available_works", force: :cascade do |t|
    t.string   "title"
    t.string   "description"
    t.string   "image"
    t.datetime "created_at",  null: false
    t.datetime "updated_at",  null: false
  end

  create_table "taggings", force: :cascade do |t|
    t.integer  "tag_id"
    t.integer  "tagged_id"
    t.string   "tagged_type"
    t.datetime "created_at",  null: false
    t.datetime "updated_at",  null: false
  end

  add_index "taggings", ["tag_id"], name: "index_taggings_on_tag_id"
  add_index "taggings", ["tagged_id"], name: "index_taggings_on_tagged_id"

  create_table "tags", force: :cascade do |t|
    t.string   "name"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end
end

<table>
  <tbody>
  <% @available_works.each do |available_work| %>
    <tr>
      <td><%= available_work.title %></td>
      <td><%= available_work.description.try(:html_safe) %></td>
      <td>Tags: <%= available_work.tag_list %></td>
      <td><%#= image_tag available_work.image_url(:thumb) %></td>
      <td><%= link_to 'Show', available_work %></td>
      <td><%= link_to 'Edit', edit_available_work_path(available_work) %></td>
      <td><%= link_to 'Destroy', available_work, method: :delete, data: { confirm: 'Are you sure?' } %></td>
    </tr>
  <% end %>
  </tbody>
</table>

Note that I commented out the images part to save time since it is not directly relevant to the question.

The Rails app I created to answer the question is available at https://github.com/maxcal/playground/tree/adding-tags-in-rails.

Upvotes: 1

Related Questions