0

I'm trying to roll my own tagging system. My setup is (at the moment) much like acts_as_taggable_on, with Tags, Taggable objects, and Taggings to relate the one to the other. Taggable is a module, which will be included in Events, Users, and probably a few other kinds of objects that will be taggable. At the moment I'm just trying to hook it up to work with Events.

I'm following Railscast #167.

In the railscast, the virtual attribute tag_names is made accessible with attr_writer :tag_names.

My problem is, I can't get the tag_names field to accept input unless I use attr_accessible :tag_names (ie, 'attr_accessible' instead of 'attr_writer').

when specifying attr_writer :tag_names, I submit the form and get the error: "Can't mass-assign protected attributes: tag_names". When I put attr_accessible :tag_names instead, it seems to work okay, but this is a security issue, right? (Please note: there isn't a tag_names field in the DB for the Event objects.)

And why can't I replicate the Railscast? I'm running Rails 3.2.11, and the Railscast is from 2009, but I can't find anything saying that attr_writer has been replaced with attr_accessible in this later version or anything like that.

Thanks for any help!

The relevant part of my Event form:

<%= f.input :tag_names, label: "Tags (separate by commas)" %>

My Event model:

class Event < ActiveRecord::Base
    include Taggable

    # Default - order by start time
    default_scope :order => 'events.start_time ASC'

    belongs_to :creator, :foreign_key => "creator_id", :class_name => "User"
    validates_presence_of :creator

    (etc)

My Taggable module:

module Taggable
    extend ActiveSupport::Concern

    included do
        has_many :taggings, :as => :taggable
        has_many :tags, :through => :taggings

        attr_accessible :tag_names
    end

    def tag(name)
        name.strip!
        tag = Tag.find_or_create_by_name(name)
        self.taggings.find_or_create_by_tag_id(tag.id)
    end

    def untag(name)
        name.strip!
        t = Tag.find_by_name(name)
        self.taggings.find_by_tag_id(t).destroy
    end

    # Return an array of tags applied to this taggable object
    def tag_list
       Tag.joins(:taggings).where(taggings: {taggable_id: self})
    end

   # Getter method for virtual attribute tag_names
   def tag_names
       @tag_names || tags.map(&:name).join(', ')
   end

   # Setter method for virtual attribute tag_names
   def tag_names=(names)
       @tag_names = names.split(",").map do |n|
           Tag.find_or_create_by_name(n.strip)
       end
   end  
end
Reb
  • 649
  • 1
  • 8
  • 12

1 Answers1

2

attr_accessible and attr_writer are two completely different things. The former is a concept pre-Rails 4 where you are whitelisting attributes that are mass-assignable. The latter is creating an instance method on your class that lets you set a value publicly, but not read it.

There are also attr_reader and attr_accessor.

attr_accessor is maybe what you're confusing with attr_accessible. This method is similar to attr_writer, except it provides both a reader and writer method. attr_reader is the opposite of attr_writer in that it gives you an instance method for reading values, but not writing them.

Peter Brown
  • 50,956
  • 18
  • 113
  • 146
  • Thanks. Thing is, I've tried nearly all of the things you mention (attr_writer and attr_accessor as well as attr_accessible). The Railscast says to use "attr_writer", and that's what I tried first, but got an error. The only way I can get around the error ("Can't mass-assign protected attributes: tag_names") seems to be to include "attr_accessible :tag_names". I know this is wrong. tag_names isn't even a field in my database. I just want to be able to submit the form and have the setter method use the comma-separated tags in the field to create multiple Tag objects. Hope that makes sense? – Reb Oct 15 '13 at 12:55
  • Just found that [this person](http://stackoverflow.com/questions/8772498/rails-virtual-attributes-wont-read-from-form-for-submission?rq=1) looks to have experienced the same problem following the same railscast. He seems to have wound up happy but I can't figure out what he did to fix it heh! – Reb Oct 15 '13 at 13:15
  • Maybe this is an issue to do with the way simple_form handles virtual attributes... – Reb Oct 15 '13 at 14:17