I'm using the acts-as-taggable-on gem to add tags on my business + service models in my Rails 6 app in order to enable users to find whatever service/business they're seeking more easily. A service will have food-specific tags available if the business is a restaurant, and more general ones if it's another type of business. Whenever I try to create either a new business or a new service, I'm getting the same error:
ActiveRecord::AssociationTypeMismatch - ActsAsTaggableOn::Tag(#755220) expected, got "" which is an instance of String(#7280):
app/controllers/services_controller.rb:12:in `create'
Here is the relevant part of my Service model code:
class Service < ApplicationRecord
belongs_to :business
acts_as_taggable_on :tags
acts_as_taggable_on :food_taggings, :service_taggings
Here's the relevant part of my new service form:
<%= simple_form_for [@business, @service] do |f|%>
<%= f.input :food_taggings, collection: Service.foodlist, input_html: {multiple: true, id: "food_tagging_new", class: "select2"}, label: "Please add some descriptive tags to the dish that you're offering so that local users could find it more easily" %>
<%= f.input :service_taggings, collection: Business.offerings, input_html: {multiple: true, id: "service_tagging_new", class: "select2"}, label: "Please add some descriptive tags to the service that you're offering so that local users could find it more easily" %>
<%= f.button :submit, 'Submit', class: 'btn btn-primary'%>
</div>
<% end %>
Here's the relevant part of my services controller code:
def create
@service = Service.new(service_params)
if @service.save
flash[:notice] = "This service was successfully added!"
redirect_to @service
else
render "new"
end
end
private
def service_params
params.require(:service).permit( :tag_list, tag_list: [], food_taggings: [], service_taggings: [] )
end
And here are the params that go along with the create new service request:
{"authenticity_token"=>"kld9sOSfro/nrINxQdKpXCZnxt6Cjb6TIw+jcjW5XmpUhvfm767dPXStOGB2vEBbckZvb87uKXlZo2KGjAo8vA==", "service"=>{"name"=>"", "description"=>"", "price_cents"=>"", "food"=>"0", "food_taggings"=>[""], "service_taggings"=>[""]}, "commit"=>"Submit", "controller"=>"services", "action"=>"create", "business_id"=>"5"}
How would I go about fixing this issue so that both of the models can get created successfully? I was already able to create some seeds for both without including any tags successfully, and I'm not sure exactly what Rails is expecting now?
To recap what acts_as_taggable_on
is doing, say you declare a single taggable attribute:
class Service < ApplicationRecord
acts_as_taggable_on :tags
end
The gem does two things:
has_many/belongs_to
) between your class and ActsAsTaggableOn::Tag
, which is how the gem models tags you define. When you access tags
on a instance of Service
, you get an array of these Tag
objects like you would with any has_many
association.tag_list
(note: singluarized), which is the main way the gem expects you to interact with tags. Calling this will do the work of querying the associated Tag
objects and return you a nice array of strings. Or you can assign it an array of strings, which get parsed into Tag
objects.In your form and controller, you are using the raw association references (food_taggings
and service_taggings
). Thus when your form POSTs, Rails properly raises an error because it is expecting those parameters to be arrays of Tag
objects not arrays of strings.
If you change your form to use the convenience wrapper names for the form fields, the gem will properly parse the array of strings in your params and create the associated objects:
<%= simple_form_for [@business, @service] do |f|%>
<%= f.input :food_tagging_list, ... %>
<%= f.input :service_tagging_list, ... %>
...
<% end %>
Don't forget to alter your permitted parameters on the controller as well:
def service_params
params.require(:service).permit(tag_list: [],
food_tagging_list: [],
service_tagging_list: [])
end