ruby error with form builder (collection), Group expected, got String - ruby-on-rails

Im new to ruby and got a problem
= simple_form_for #user do |f|
.form-inputs
= f.input :name
= f.input :email
= f.input :group_id, collection: Group.all.collect {|c| [c.name, c.id]}
.form-actions
= f.button :submit
The line that gives me an error message is this:
= f.input :group, collection: Group.all.collect {|c| [c.name, c.id]}
Same thing with
= f.input :group, collection: #groups
The User:
class User < ActiveRecord::Base
attr_accessible :email, :name, :group
belongs_to :group
The Group:
class Group < ActiveRecord::Base
attr_accessible :description, :name
has_many :users
I was also using the gem "immigration", which created the foreign key and this migration:
class AddKeys < ActiveRecord::Migration
def change
add_foreign_key "users", "groups", :name => "users_group_id_fk"
end
end
I saw the warning here about collections and form builders.
When I use
= f.input :group_id, collection: #groups
it prompts me an error message even before loading the page (not after submitting the form)
undefined method `group_id'
any help?

According to the Simple Form documentation, you should use f.input :group, and not f.input :group_id. The beauty is that you don't have to pass in the collection, it does it automagically:
f. input :group
This should render a select input with your groups listed.

Change your model from Group to XGroup or anything other than Group, I think you're conflicting with ActiveRecord's Group

Related

has_one relation in form in active admin

I have two models/tabels: room and room_location, that have a one on one relation:
class Room < ApplicationRecord
has_one :room_location
end
class RoomLocation < ApplicationRecord
belongs_to :room
end
And this is what i want to do in my form in rooms.rb:
ActiveAdmin.register Room do
menu parent: 'Rooms'
permit_params :name, :description, room_location_attributes: [:address, :city]
form do |f|
f.inputs 'Roomsdata' do
f.input :name, as: :string
f.input :description
f.has_one :room_location do |t|
t.inputs do
t.address
t.city
end
end
f.actions
end
end
end
The has_one doesnt work and if i do has_many, it says relation "room_locations" does not exist
You should write in the params room_location_id instead of attributes
ActiveAdmin.register Room do
menu parent: 'Rooms'
permit_params :name, :description, room_location_id
form do |f|
address_id = ''
cs = params[:id].present? ? Case.find(params[:id]) : nil
unless cs.nil?
address_id = cs.address.id unless cs.address.nil?
end
f.inputs 'Roomsdata' do
f.input :name, as: :string
f.input :description
f.input :room_location_id , :as => :select, :collection => room_location.order(address: :desc).to_a.uniq(&:address).collect {|room_location| [room_location.address, room_location.id] }, selected: room_location_id
f.input :room_location_id , :as => :select, :collection => room_location.order(city: :desc).to_a.uniq(&:city).collect {|room_location| [room_location.address, room_location.id] }, selected: room_location_id
f.actions
end
end
end

Rails - Set additional attribute on has_many through record

Using Rails 6.0.3.3 and ruby '2.6.0'.
I have these 3 models connected via a has_many through relation.
class Recipe < ApplicationRecord
has_many :layers
has_many :glazes, through: :layers
end
class Glaze < ApplicationRecord
has_many :layers
has_many :recipes, through: :layers
end
class Layer < ApplicationRecord
belongs_to :recipe
belongs_to :glaze
# there is a column named "coat_type" here that I would like to set
end
Everything is working great for creating a new Recipe and it automagically creating its related Layer record. But now I would like to also set a coat_type attribute on the Layer record when it's created, but I can't seem to figure out how I could do something like that.
The Form View Partial
= form_with model: recipe, local: true do |form|
%p
= form.label :name
%br
= form.text_field :name
%p
= form.label :description
%br
= form.text_area :description
.recipe-glaze
= form.collection_select(:glaze_id, Glaze.all, :id, :name, { prompt: "Select Glaze" }, { name: 'recipe[glaze_ids][]' })
.recipe-glaze
= form.collection_select(:glaze_id, Glaze.all, :id, :name, { prompt: "Select Glaze" }, { name: 'recipe[glaze_ids][]' })
%p
= form.submit
The Controller Create Action (and strong params acton)
def create
#recipe = Recipe.new(recipe_params)
if #recipe.save
redirect_to #recipe
else
render 'new'
end
end
private
def recipe_params
params.require(:recipe).permit(:name, :description, glaze_ids: [])
end
Ideally, I would be able to add another select box in the form and the user would use that to set the coat_type of the Layer record that will be created. But I can't figure out how I could pass that into the controller and have it know what to do with that value.
Is this something that is possible, or am I approaching this incorrectly?
So I actually ended up stumbling upon the "cocoon" gem thanks to this comment. By following the setup instructions for "cocoon", I was able to tweak my code to do what I needed.
My Recipe model changed to this ::
class Recipe < ApplicationRecord
has_many :layers, inverse_of: :recipe
has_many :glazes, through: :layers
accepts_nested_attributes_for :layers, reject_if: :all_blank, allow_destroy: true
end
My controller's strong params action changed to this ::
private
def recipe_params
params.require(:recipe).permit(:name, :description, layers_attributes: [:id, :glaze_id, :coat_type, :_destroy])
end
My form view partial changed to ::
- if recipe.errors.any?
= render partial: 'errors', locals: { recipe: recipe }
%p
= form.label :name
%br
= form.text_field :name
%p
= form.label :description
%br
= form.text_area :description
%h3 Layers
#layers
= form.fields_for :layers do |layer|
= render 'layer_fields', f: layer
.links
= link_to_add_association 'add layer', form, :layers
%p
= form.submit
and the "layer_fields" partial referenced in the form looks like this ::
.nested-fields
.field
= f.label :glaze_id
%br
= f.collection_select(:glaze_id, Glaze.all, :id, :name, { prompt: "Select Glaze" } )
.field
= f.label :coat_type
%br
= f.text_field :coat_type
= link_to_remove_association 'remove layer', f
Making those changes using the "Cocoon" gem, I was able to accomplish what I needed. Hopefully this helps someone else in the future.

Pass current_admin_user.id into permit_params

In my application I have 2 models: AdminUser, which has_many :announcements, and Announcement, which belongs_to :admin_user. The Announcement table has admin_user_id column in a database.
In app/admin/announcement.rb I have:
ActiveAdmin.register Announcement do
permit_params :title, :body, :admin_user_id
controller do
def new
#announcement = Announcement.new
#announcement.admin_user_id = current_admin_user.id
end
end
form do |f|
f.inputs do
f.input :title
f.input :body, as: :ckeditor
end
f.actions
end
end
Why my controller doesn't work? When I create an announcement through activeadmin, the column admin_user_id is empty. How can I solve this issue?
Just added to a form: f.input :admin_user_id, as: :hidden, and now everything is working.

Creating a record with Associations - Active Admin

I am using active admin and seem to be struggling with creating a record with an association. I have set this up in the normal way
class Membership < ActiveRecord::Base
belongs_to :member
attr_accessible :membership_type
end
class Member < ActiveRecord::Base
has_one :membership
accepts_nested_attributes_for :membership
attr_accessible :membership_attributes, :forename, :middlename, :surname, :house_no, :house_name, :street, :town, :postcode, :home_tel, :mobile_tel, :work_tel, :email
end
I then want to create a New member along with their membership type in the same form, so my member.rb looks like this so far
ActiveAdmin.register Member do
# Set Which Columns are to be displayed on the index page
index do
column :forename
column :middlename
column :surname
column :house_no
column :house_name
column :street
column :town
column :postcode
column :home_tel
column :mobile_tel
column :work_tel
column :email
column :membership do |member|
member.membership.map{ |ms| ms.membership_type}
end
default_actions
end
# Set Which Columns are to be displayed on Create New Member
form do |f|
f.inputs "Member Registration" do
f.input :forename
f.input :middlename
f.input :surname
f.input :house_no
f.input :house_name
f.input :street
f.input :town
f.input :postcode
f.input :home_tel
f.input :mobile_tel
f.input :work_tel
f.input :email
end
f.inputs :for => [:membership, f.object.membership || Membership.new] do |m|
m.input :membership_type, :label => 'Membership Type', :as => :select, :collection => Membership.all.map{|m| [m.membership_type]}
end
f.actions
end
end
This displays a select box where i can choose from various Membership types, but i dont seem to be passing the correct value when creating the record,
This is an example of what is being posted
member[forename]:Name 1
member[middlename]:Name 2
member[surname]:Name 3
member[house_no]:1
member[house_name]:
member[street]:Test Street
member[town]:Test Town
member[postcode]:CF23 7BD
member[home_tel]:01633222222
member[mobile_tel]:07864582356
member[work_tel]:01633555555
member[email]:test#mail.com
membership_attributes"=>{"membership_type"=>"Student"}
commit:Create Member
This doesn't seem right does it? Also when i try and view the record
column :memberships do |member|
member.memberships.map{ |ms| ms.membership_type}
end
I get the following mysql error
Mysql2::Error: Unknown column 'memberships.member_id' in 'where clause': SELECT `memberships`.* FROM `memberships` WHERE `memberships`.`member_id` = 10
Could anyone point me in the right direction please or can anyone see where im going wrong?
Much appreciated
Instead of f.input :memberships try this:
f.has_many :memberships do |pf|
pf.input :membership_type
end
and close your member object fields like this
f.inputs "Member Registration" do
f.input :forename
f.input :middlename
f.input :surname
...
end
So your form should look like this:
form do |f|
f.inputs "Member Registration" do
f.input :forename
f.input :middlename
f.input :surname
# .. the rest of your fields
end
f.has_many :memberships do |pf|
pf.input :membership_type
end
f.actions
end
Regarding the MySQL error, i think for the association to work you need to add the column member_id to the memberships table. You can create the migration with
rails g migration add_member_id_to_memberships member_id:integer
Then migrate with
bundle exec rake db:migrate

Accessing error messages for nested attribute field

I have a form created using the simple_form gem which populates 2 models using nested attributes. I want to check if there are any errors and display a new block. However, I'm not sure how to correctly access the error message for the location attribute of the Booking model.
class Booking < ActiveRecord::Base
belongs_to :customer
attr_accessible :date_wanted, :location
end
and
class Customer < ActiveRecord::Base
has_many :bookings
accepts_nested_attributes_for :bookings
attr_accessible :name, :phone, :bookings_attributes
validates_presence_of :name, :phone
end
Form view:
simple_form_for #customer, {:html => { :class => "form-horizontal" }} do |f|
= f.input :name
= f.input :phone
= f.simple_fields_for :bookings do |b|
= b.input :date
= b.input :location
- if #customer.errors[:appointments_attributes][:location]
# insert code if any validation errors for the date field were found
= f.button :submit
b is an instance of form builder, holding booking, so you can try:
# ...
if b.object.errors[:location]
# ...

Resources