Rails 5.2: collection_select with has_many through form - ruby-on-rails

I have a setup where an author has many sources (and visa versa) through authorships.
I am working on the source form and would like to have a selection dropdown where a user can select multiple authors to be associated with a given source.
My author model looks like this:
class Author < ApplicationRecord
belongs_to :user
has_many :authorships
has_many :sources, through: :authorships
def last_first
"#{last_name}, #{first_name}"
end
...
end
My source model:
class Source < ApplicationRecord
belongs_to :user
has_many :authorships
has_many :authors, through: :authorships
...
end
And my authorship model:
class Authorship < ApplicationRecord
belongs_to :source
belongs_to :author
end
I tried this at first:
<%= f.collection_select(:author_ids, Author.all, :id, :last_first, multiple: true) %>
But I got this strange error: Could not find the source association(s) "author" or :authors in model Authorship. Try 'has_many :authors, :through => :authorships, :source => <name>'. Is it one of ?
I consulted many SO posts like this, this, and this, but to no avail.
Can anyone help me figure out what I'm doing wrong? The collection_select documentation is not much help.

I ended up solving this with a collection_check_boxes like this:
<%= f.collection_check_boxes :author_ids, Author.all, :id, :last_first do |b| %>
<div class="field form-check" style="display: block">
<%= b.check_box class: "form-check-input" %>
<%= b.label class: "form-check-label" %>
</div>
<% end %>
Not a dropdown, but it's functional and saves!

Related

Using a Many-to-Many Relationship with the Public Activity gem in Rails

I have the scenario where an author has and belongs to many books, vice versa. Following the instructions for setting up associations in a one-to-many relationship works fine but when a many-to-many relationship introduced I get this error message whenever I try to create or update my book model.
undefined method `author' for #<Book:0x007fb91ae56a70>
As far as setting up how authors are chosen for a book I'm using the code provided by the token-input railscast here with a few alterations.
class Author < ActiveRecord::Base
has_many :authorships
has_many :books, through: :authorships
def self.tokens(query)
authors = where("name like ?", "%#{query}%")
if authors.empty?
[{id: "<<<#{query}>>>", name: "Add New Author: \"#{query}\""}]
else
authors
end
end
def self.ids_from_tokens(tokens)
tokens.gsub!(/<<<(.+?)>>>/) {create!(name: $1).id}
tokens.split(',')
end
end
class Book < ActiveRecord::Base
attr_reader :author_tokens
include PublicActivity::Model
tracked owner: :author
has_many :authorships
has_many :authors, through: :authorships
def author_tokens=(ids)
self.author_ids = Author.ids_from_tokens(ids)
end
end
Form View
<%= form_for(#book) do |f| %>
...
<div class="field">
<%= f.text_field :author_tokens, label: 'Author', input_html: {"data-pre" => #book.authors.to_json} %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
There is no author relationship in your Book model.
What
tracked owner: :author
does is basically calling method author on your Book instance. You should try :authors
But!
That won't solve your problem because owner can only be one. So you can do something like:
tracked owner: proc {|_, book| book.authors.first }
to set the owner to the first author the book has.
class Author < ActiveRecord::Base
has_many :author_books, inverse_of: :author, dependent: :destroy
accepts_nested_attributes_for :author_books
has_many :books, through: :author_books
end
class Book < ActiveRecord::Base
has_many :author_books, inverse_of: :book, dependent: :destroy
accepts_nested_attributes_for :author_books
has_many :authors, through: :author_books
end
class AuthorBook < ActiveRecord::Base
validates_presence_of :book, :author
end
============= view ==============
<%= form_for #book do |f| %>
<%= f.text_field :title %>
<%= f.fields_for :author_books do |f2| %>
<%# will look through all author_books in the form builder.. %>
<%= f2.fields_for :author do |f3| %>
<%= f3.text_field :name %>
<% end %>
<% end %>
<% end %>

Has_many through checkboxes (simple_form) not saving

I am trying to sort comments into events using a has_many :through association using checkboxes however the selected events are not saved. Here are my models:
class Comment < ActiveRecord::Base
has_many :categorizations
has_many :events, :through => :categorizations
end
class Event < ActiveRecord::Base
has_many :categorizations
has_many :comments, :through => :categorizations
end
class Categorization < ActiveRecord::Base
belongs_to :comment
belongs_to :event
end
My comments form looks like this:
<%= simple_form_for [#post, #comment] do |f| %>
<%= f.input :title %>
<%= f.association :events, :as => :check_boxes %>
<%= f.submit "Save" %>
After reading this answer, I added this to my event and comment controllers with no luck:
def comment_params
params.require(:comment).permit(:post_id, :title, :categorization_ids => [])
end
Try:
def comment_params
params.require(:comment).permit(:post_id, :title, :event_ids => [])
end
It's hard to know what's going on though without recreating it or seeing server logs, Hopefully this will solve it.

How can I create a has_many through record using simple form ? I

My Category model :
class Category < ActiveRecord::Base
has_many :item_categoryships
has_many :items, :through => :item_categoryships
end
My Item model :
class Item < ActiveRecord::Base
has_many :item_categoryships
has_many :categories, class_name: 'ItemCategoryship', foreign_key: 'category_id', :through => :item_categoryships
end
My ItemCategoryship model:
class ItemCategoryship < ActiveRecord::Base
belongs_to :item
belongs_to :category
end
And in views/items/edit.html.erb, I wrote simple form code like this:
<%= simple_form_for(#item) do |f| %>
<%= f.association :categories, collection: #categories, as: :check_boxes %>
<%= f.submit "Submit", class: "btn btn-large btn-primary" %>
<% end %>
The #categories above, I wrote this in controller:
#categories = current_user.categories
But I hit a problem, they can't save to database!!
I couldn't find out what the problem was. Please help me....
Thanks you all.
For the view, this SO answer should help:
https://stackoverflow.com/a/9917006/2463468
You may first need to make sure your associations make sense. Perhaps you only need a has_many on Items and belongs_to on Category.
You might be able to do without ItemCategoryship.

How do I include has_many relationships in a Rails form?

I have two models, Artist and User that are connected through a third model, ArtistMembership.
From the edit/new Artist form, I want to be able to edit the role of any User in an existing ArtistMembership relationship for that Artist, delete ArtistMemberships, and add new AtistMembership relationships, which would include a User and :role.
Here's my Artist model:
class Artist < ActiveRecord::Base
has_many :artist_memberships, foreign_key: "artist_id", dependent: :destroy
attr_accessible :bio, :created_at, :email, :location, :name, :updated_at, :website, :pic
accepts_nested_attributes_for :artist_memberships, :allow_destroy => :true
...
end
Here's my User model:
class User < ActiveRecord::Base
...
has_many :artist_memberships, foreign_key: "user_id"
...
end
Here's my ArtistMembership model:
class ArtistMembership < ActiveRecord::Base
belongs_to :artist, class_name: "Artist"
belongs_to :user, class_name: "User"
attr_accessible :artist_id, :created_at, :role, :user_id
end
If I have a _form.hml.erb too, for editing Artists that starts:
<%= form_for #artist do |artist_form| %>
<div class="field">
<%= artist_form.label :name %>
<%= artist_form.text_field :name %>
</div>
..
<div class="actions">
<%= artist_form.submit %>
</div>
<% end %>
how can I create the related ArtistMembership forms for the aforementioned functionality?
May be this is helpful for you, see this field_for
you can use accepts_nested_attributes_for(*attr_names)
Maybe you are looking for this method.
http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-fields_for
Refer to the "One-to-many" section.
But if I were you, I would rather use the "Nested Resource" technic.
http://guides.rubyonrails.org/routing.html#nested-resources

Rails has many through relationships

I am using rails has_many through options and not sure if I am doing something wrong here. I would like for a player to create a season and when a player is about to create a season it will show a select menu of all the seasons I have created in years/new. So far that part has worked great but when a player try's to save the season rails does not save it. I am not sure if my association is correct or if I am doing something wrong? Is there any reason why this is not working?
error
No association found for name `season_year'. Has it been defined yet?
season.rb
class season < ActiveRecord::Base
belongs_to :player
has_many :quarters
has_many :years , :through => :quarters
attr_accessible :season_year_attributes
accepts_nested_attributes_for :season_year
end
quarter.rb
class Quarter < ActiveRecord::Base
belongs_to :player
belongs_to :year
belongs_to :season
end
year.rb
class Year < ActiveRecord::Base
attr_accessible :season_year, :season_name
has_many :quarters
has_many :seasons, :through => :quarters
end
player.rb
class player < ActiveRecord::Base
has_many :seasons, :through => :quarters
has_many :years, :through => :quarters
end
_season-form.html.erb
<%= form_for(#season) do |f| %>
<div class="field">
<%= f.label :season %>
<%= f.text_field :season_name %>
</div>
<%= f.fields_for :years do |year| %>
<%= select("season", "year_ids", Year.all.collect {|p| [ p.season_year, p.id ] }, { :include_blank => true }) %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Based on your models, I believe you need to change this:
accepts_nested_attributes_for :season_year
to this:
accepts_nested_attributes_for :years
When you accept nested attributes it is for a Model and not a property of a model (season_year is an attribute of the year model versus accepting the nested attributes for the actual model, Year).
EDIT:
In the Season model, I added year_ids to the attr_accessible expression:
attr_accessible :season_year_attributes, :year_ids
I also altered the season form so that the output of the select list for years was only this:
<%= select("season", "year_ids", Year.all.collect {|p| [ p.title, p.id ] }, { :include_blank => true }) %>
You don't have any season_year in your Season class, that is the answer.
Did you intend to have this as an association?

Resources