Activerecord::Associationtypemismatch in Controller#Create on Dropdown Select for a Rails Self Join

ActiveRecord::AssociationTypeMismatch in Controller#create on dropdown select for a Rails self join

Lee -

Your Quote and Artist models look OK. Your schema, however, is wrong. It should look like:

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

create_table "quotes", force: :cascade do |t|
t.integer "user_id"
t.integer "speaker_id"
t.integer "topic_id"
t.text "content"
t.string "source"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end

Note speaker_id and topic_id instead of artist_id.

I'd need to see your stack trace to see what might be wrong with how you have other things set up.

BTW, have you fixed your params whitelist? This is wrong:

def quote_params
params.require(:quote).permit(:content, :source, :topic, :artist_id)
end

Since your params look like:

Parameters: {"utf8"=>"✓", "authenticity_token"=>"7xXgP3T1ZyxVhnr9TtBxeuYSRLBiuX01JSkQ4m4rN9pBS1W0iW6TJtsS7KyvunpCIZFiFltmdEwZGIYqsnxbyw==", "quote"=>{"topic_id"=>"2", "speaker_id"=>"1", "content"=>"asdfadsf", "source"=>"http://fuzz.com"}, "commit"=>"Post"}

It should be:

def quote_params
params.require(:quote).permit(:content, :source, :topic_id, :speaker_id)
end

As a shot in the dark, try changing:

validates :speaker, uniqueness: {scope: :topic}
validates :topic, uniqueness: {scope: :speaker}

To:

validates :speaker_id, uniqueness: {scope: :topic_id}
validates :topic_id, uniqueness: {scope: :speaker_id}

I'll update with explanation if that's the problem.

RAILS || ActiveRecord::AssociationTypeMismatch: Error on new model object

where always returns an ActiveRecord relation, find returns a single instance. You can use where like this for similar effect

@user.pay = Pay.where(years: @user.years).first

however a better way would be

@user.pay = Pay.find_by(years: @user.years)

ActiveRecord::AssociationTypeMismatch error when I run my create method?

Change your form like this (I renamed @category to @categories as well):

= simple_form_for @post do |f|
= f.input :title
= f.input :content
= f.input :category_id, collection: @categories, label_method: :name, value_method: :id
= f.submit

Also in controller:

def post_params
params.require(:post).permit(:title, :content, :category_id)
end

Error in you code was associated with the fact, that by default SimpleForm considers collection as an array of strings. So :category parameter was given a String value, while it should be Category.

How do you use a single select dropdown with Rails has_many through association?

Yes! exactly, I had the same problem but I have solved by using own tricks, see the below code

<div class="form-group">
<label>Artist</label>
<select name="quote[artist_ids][]" id="quote_artist_ids" class="form-control">
<% Artist.all.each do |artist| %>
<option value="<%= artist.id %>">
<%= artist.name %>
</option>
<% end %>
</select>
</div>

It's working, without this everything are same like: quote_params I mean all are the same which before worked for multiple.

Hope to help

Combining elements in select dropdown while maintaining correct id in association

I figured it out. All I had to do is add a array inside the collection block with the first item displayed and the second item as the id. So it should look like this:

collection: Student.all.map{|s| ["#{s.firstname} #{s.lastname}",s.id] }

How do you structure a rails model where two attributes need to share the same association with another model?

I believe you want Quote to look something like:

class Quote < ActiveRecord::Base
belongs_to :speaker, class_name: "Artist"
belongs_to :subject, class_name: "Artist"
belongs_to :user

validates :speaker, uniqueness: {scope: :subject}
validates :subject, uniqueness: {scope: :speaker}

...

end

This assumes:

  • A User (probably current_user or something like that) is creating the quote and that the quote belongs to that user.
  • An Artist is a distinct notion from User. That is, an Artist is not necessarily a User (a Quote may have David Bowie as a subject, but David Bowie may not be a User of your system (especially given that he has passed away as has Lou Reed)).

This way, both speaker and subject are specified as being of the class Artist.

The uniqueness validations ensure that a speaker is never a subject and visa-versa. (You may need to twiddle with the validates statement as I did not test.)

In your Artist model, you probably want to do something like:

class Artist < ActiveRecord::Base
has_many :spoken_quotes, class_name: "Quote", foreign_key: :speaker_id
has_many :referencing_quotes, class_name: "Quote", foreign_key: :subject_id

...

end

That way, you could do something like:

Artist.find_by(name: 'David Bowie').spoken_quotes

And get all the Quotes for which David Bowie is the speaker.

And, in your User model, you probably want something like:

class User < ActiveRecord::Base
has_many: :quotes

...

end

So that you can do something like:

current_user.quotes

And get all the quotes the current_user has created.

Rails: How to pass index object into controller for further sorting?

I think your code will be much clearer and reusable if you don't directly call index() from list_open_process, but instead move the part that populates @quotes to another method or object. For instance:

def index
# do other stuff first?
@quotes = get_quotes
end

def list_open_process
@quotes = return_open_process(get_quotes)
end

def get_quotes
# extracted from the index() method
end
private :get_quotes

Now, the intention is clearer, and you aren't doing any extra steps that index might execute that aren't needed by list_open_process.

As for making it more flexible, depending on size you might consider a case statement that matches a param string like 'quotes' to the method that gets quotes, and so on. Or use a hash of keywords to method references. The point is, you want to make sure that you ONLY execute code when an allowed keyword type is passed, and any other ones get ignored or trigger an error message back to the client.

How to validate the uniqueness on a form instance and not the entire database in Rails?

Multiple occurences of an Artist both as a speaker and a topic, are at the core of your model logic; I don't think there is any uniquenessto validate at all - neither scoped or conditional. Validation that you want considers only context of single instance of a Quote; I believe it should be a custom one.

validate :topic_cant_be_a_speaker

def topic_cant_be_a_speaker
errors.add(:speaker, "Topic can't be a speaker") if speaker == topic
end


Related Topics



Leave a reply



Submit