I am trying to create a drop-down-select menu that users can be selected from. I want to also have the number of projects they are assigned to displayed next to their name
class User < ActiveRecord::Base
attr_accessible :email, :username, :password, :password_confirmation, :remember_me, :first_name, :last_name
belongs_to :department
has_many :project_assignments
.
class ProjectAssignment < ActiveRecord::Base
attr_accessible :user_id, :project_id, :active, :notes
belongs_to :user, counter_cache: :projects_count
belongs_to :project
end
.
class Project < ActiveRecord::Base
attr_accessible :program_id, :title, :status, :topic_number, :award_number, :task_data_attributes, :user_ids, :technical_poc_id, :contacts_attributes, :project_fields_attributes, :division_id, :company_name
attr_accessor :old_project_id
belongs_to :program
belongs_to :division
belongs_to :company
has_many :users, through: :project_assignments
.
<div class="col-md-12">
<p>New Assignment</p>
<%= form_for #project.project_assignments.new, url: program_project_assignments_path(#program, #project), html: { id: 'staff-form' } do |f| %>
<%= f.select :user_id, options_from_collection_for_select(User.all, :id, :full_name), {}, class: 'form-control input-sm', placeholder: 'User' %>
<%= hidden_field_tag "project_id",nil,:value => #project.id %>
<%= f.submit 'Assign', class: 'btn-gray' %>
<% end %>
</div>
All the above code is just excerpts from their respective files. The above html works for populating the drop-down with names, but obviously no code there is attempting to add the number of assigned projects
Use options_for_select
<%= f.select :user_id, options_for_select(User.all.collect{|u|["#{u.full_name} #{u.project_assignments.count}", u.id]}), {}, class: 'form-control input-sm', placeholder: 'User' %>
It will be efficient to load the users and eager load project assignment in your controller
#users = User.includes(:project_assignment).all
Related
I have three models: Course, Category, and Categorisation.
# course.rb
class Course < ApplicationRecord
has_many :categorisations, foreign_key: "course_id", dependent: :destroy
has_many :categories, through: :categorisations
end
#category.rb
class Category < ApplicationRecord
has_many :categorisations, foreign_key: "category_id", dependent: :destroy
has_many :courses, through: :categorisations
end
# categorisation.rb
class Categorisation < ApplicationRecord
belongs_to :course
belongs_to :category
validates :course_id, presence: true
validates :category_id, presence: true
end
Course controller has the following params:
def course_params
params.require(:course).permit(:name, :prerequisite, :description,
:user_id, :category_ids => [])
end
I'm trying to build the association via the Course form:
<%= form_for #course do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control' %>
<%= f.label :prerequisite %>
<%= f.text_field :prerequisite, class: 'form-control' %>
<%= f.label :description %>
<%= f.text_area :description, class: 'form-control' %>
<%= f.label :category_ids, "Category" %>
<%= f.collection_check_boxes :category_ids, Category.all, :id, :name,
{}, { multiple: true, class: 'form-control'} %>
<%= f.submit "Create a new course", class: "btn btn-primary" %>
<% end %>
However when I click submit I get the validation error:
Categorisations is invalid
I'm unsure why this is the case?
Removing the presence validation on :course_id will fix the issue
class Categorisation < ApplicationRecord
belongs_to :course
belongs_to :category
# validates :course_id, presence: true
validates :category_id, presence: true
end
Problem:
Course is not saved but due to through association when you associate category with course rails first tries to save categorisation but course_id is not available yet
And this is the reason presence validation fails for course_id
Solution
Removing the validation is just a workaround the actual solution will be something interesting
NOTE: Even I am facing the similar issue a few days back. we have removed validation for now. I will be interested in any better solution
You're not able to save any entity that relates to Categorization in database because of presence: true action. Firstly, I think it's a better idea to validate :category_id in the schema.rb by category_id null: false. And secondly, are you sure you need the Categorization model? My suggestion is to think of putting a categorizationable.rb file in your yourApp/app/models/concerns folder and after that using its functionality in the existing models. You can read more about concerns here. This technique is really powerful when your models need refactoring.
In my app users has many companies, and companies has many users, companies has many divisions and users have different division in different company for example User with id 1 belongs to Company 1 and Division 2 and to Company 2 Division 3
User.rb
class User < ActiveRecord::Base
has_many :companies, through: :users_companies
has_many :users_companies
has_many :divisions, through: :users_divisions
has_many :users_divisions
has_many :users_roles, dependent: :destroy
has_many :roles, through: :users_roles
end
Company.rb
class Company < ActiveRecord::Base
#before_create :create_division
has_many :users_companies
has_many :users, through: :users_companies
has_many :divisions, dependent: :destroy
has_many :positions
end
Division.rb
class Division < ActiveRecord::Base
has_ancestry
belongs_to :company
has_many :users, through: :users_divisions
has_many :users_divisions
end
UsersCompany.rb
class UsersCompany < ActiveRecord::Base
belongs_to :user
belongs_to :company
end
UsersDivision.rb
class UsersDivision < ActiveRecord::Base
belongs_to :user
belongs_to :division
belongs_to :company
end
UsersDivision table have structure
id|user_id|division_id|company_id
when create all be fine
UsersDivision.create!(user: #user, division_id: params[:user][:division_ids], company_id: #company.id)
but when I try to update #user in table UsersDivision column company_id will be nill.
def update
#company = Company.find(params[:company_id])
#user = User.find(params[:id])
if #user.update(user_params)
redirect_to :back
end
end
How to pass params :company_id to update action?
<div class="edit-registration-container">
<%= #user.full_name %>
<%= form_for([#company, #user]) do |f| %>
<%= f.label :last_name, "Фамилия" %><br />
<%= f.text_field :last_name, type: "text" %>
<%= f.label :first_name, "Имя" %><br />
<%= f.text_field :first_name, type: "text" %>
<%= f.label :middle_name, "Отчество" %><br />
<%= f.text_field :middle_name, type: "text" %>
<%= f.label :division_ids, "Подразделение" %><br />
<%= f.select :division_ids, #divisions_select %><br />
<%= f.hidden_field :company_id, value: #company.id %>
<%= f.fields_for :positions, #position do |ff| %>
<%= ff.label :name, "Должность" %>
<%= ff.text_field :name, type: "text" %>
<%= ff.hidden_field :company_id, value: #company.id %>
<% end %>
<%= hidden_field_tag "user[role_ids][]", nil %>
<% Role.all.each do |role| %>
<%= check_box_tag "user[role_ids][]", role.id, #user.role_ids.include?(role.id), id: dom_id(role) %>
<%= label_tag dom_id(role), role.name %><br>
<% end %>
<%= f.submit "Сохранить", class: "login loginmodal-submit", type: "submit" %>
<% end %>
</div>
You need to permit that parameter to be accessible, so add it in your
user controller params permit:
params.require(:user).permit(YOUR PARAMETERS, {:company_id => []})
Then you can call it using:
params["user"]["company_id"]
I think you can simply do this inside your update action:
#company = Company.find(params["user"]["company_id"])
Here is my working example form:
<%= form_for :user, :url => custom_users_path do |f| %>
<%= f.text_field :name %>
<%= f.hidden_field :company_id, :value => Company.find(1).id %> #4
<%= f.submit "Submit" %>
After I submit, inside my custom action my params["user"]["company_id"] would have this value: 4
I want the user to search through existing items from the items table in the orders form, it works for clients but not for items, it gives an error: Association :item not found
Models
class Order < ActiveRecord::Base
belongs_to :user
belongs_to :client
has_many :order_items
has_many :items, :through => :order_items
end
class Item < ActiveRecord::Base
has_many :order_items
has_many :orders, :through => :order_items
end
class OrderItem < ActiveRecord::Base
belongs_to :item
belongs_to :order
end
Migration
class CreateOrderItems < ActiveRecord::Migration
def change
create_table :order_items do |t|
t.integer :item_id
t.integer :order_id
t.timestamps
end
add_index :order_items, [:item_id, :order_id]
end
end
View
<%= simple_form_for(#order) do |f| %>
<%= f.error_notification %>
<%= f.association :client, collection: Client.all, label_method: :name, value_method: :id, prompt: "Choose a Client", input_html: { id: 'client-select2' } %>
<%= f.association :item, collection: Item.all, label_method: :name, value_method: :id, prompt: "Choose an item", input_html: { id: 'client-select2' } %>
<%= f.input :memo, label: 'Comments' %>
<%= f.submit %>
<% end %>
Controller
def new
#order = Order.new
end
def create
#order = Order.new(order_params)
#order.user_id = current_user.id
#order.status = TRUE
end
def order_params
params.require(:order).permit(:code, :client_id, :user_id, :memo, :status, items_attributes: [:id, :name, :price, :quantity, :status, :_destroy])
end
Answer
In the form use instead:
using rails-select2 gem
<%= f.association :items, collection: Item.all, label_method: :name, value_method: :id, prompt: "Choose an item", input_html: { id: 'item-select2' } %>
or without select2
<%= f.select :item_ids, Item.all.collect {|x| [x.name, x.id]}, {}, multiple: true %>
Thanks to JKen13579
The reason that you're receiving the error for item but not for client is because there is one client associated to an order, but more than one item associated to an order. It's saying :item not found because you should be using :items (note the plural).
To allow multi-select for your order's items, replace your f.association item line with:
<%= f.select :item_ids, Item.all.collect {|x| [x.name, x.id]}, {}, multiple: true %>
And then in your controller, be sure to permit item_ids. In addition, you don't need item_attributes, because you're not using accepted_nested_attributes_for :items.
def order_params
params.require(:order).permit(:code, :client_id, :user_id, :memo, :status, item_ids: [])
end
See this SO answer for more information about has_many :through multi-select.
I have a problem that's really confusing me.
I have four models, a Workout model, an Exercise model, a workout_exercise join model, and a workout_exercise_set model.
I can add exercises to workouts through the workout_exercises join table. Now I'm trying to add sets to exercises in workouts, which is what the workout_exercises_sets table is for.
Here's an example.
Workout
Exercise 1
Set 1
Set 2
Set 3
Exercise 2
Set 1
Set 2
Set 3
Exercise 3
etc.
In workouts/edit.html.erb I have a form where I can see all the exercises in the workout, and edit the number of sets by using form_for and fields_for, but when I try to update an exercise or the entire workout I get a MassAssignmentSecurity::Error in WorkoutsController#update that says Can't mass-assign protected attributes: workout_exercise_sets. I can't figure out how to get past this. I know I'm editing a workout, but I'm not trying to write to a field called workout_exercise_sets, so I'm really confused here. I really appreciate any guidance. All relevant code is below.
workout/edit.html.erb:
<%= form_for(#workout) do |f| %>
<%= f.label :name %><br />
<%= f.text_field :name %><br />
<%= f.label :description %><br>
<%= f.text_area :description %></br>
<%= f.fields_for :workout_exercises do |s| %>
<%= s.object.exercise.name %></b>
<%= s.fields_for :workout_exercise_sets do |set| %>
<%= set.label :set_number %>:
<%= set.number_field :set_number %>
<%= set.label :reps %>:
<%= set.number_field :repetitions %>
<%= set.label :rest_time %>(seconds):
<%= set.number_field :rest_time %>
<%= set.submit %>
<% end %>
<%= s.hidden_field :_destroy %>
<%= link_to "Remove exercise?", '#', class: "remove_fields" %>
<% end %>
<%= f.submit %>
<% end %>
Here is the workout model:
class Workout < ActiveRecord::Base
attr_accessible :name, :exercises_attributes, :workout_exercises_attributes, :exercise_order, :description
has_many :workout_exercises, dependent: :destroy, :order => "exercise_order DESC"
has_many :exercises, through: :workout_exercises
accepts_nested_attributes_for :exercises
accepts_nested_attributes_for :workout_exercises, allow_destroy: :true
end
Here is the exercise model:
class Exercise < ActiveRecord::Base
attr_accessible :name, :description
has_many :workout_exercises
has_many :workouts, through: :workout_exercises
validates :name, uniqueness: :true, presence: :true
validates :description, uniqueness: :true, presence: :true
end
Here is the workout_exercise model:
class WorkoutExercise < ActiveRecord::Base
attr_accessible :exercise_id, :workout_id
belongs_to :exercise
belongs_to :workout
has_many :workout_exercise_sets, dependent: :destroy
accepts_nested_attributes_for :workout_exercise_sets, allow_destroy: :true
end
and finally, here is the workout_exercise_sets model:
class WorkoutExerciseSet < ActiveRecord::Base
attr_accessible :repetitions, :rest_time, :set_number, :workout_exercise_id
belongs_to :workout_exercise
end
And for good measure, here is a diagram of the DB:
I think in your workout_excercise.rb file, you should add :workout_exercise_sets_attributes to your attr_accessible list.
class WorkoutExercise < ActiveRecord::Base
attr_accessible :exercise_id, :workout_id, :workout_exercise_sets_attributes
belongs_to :exercise
belongs_to :workout
has_many :workout_exercise_sets, dependent: :destroy
accepts_nested_attributes_for :workout_exercise_sets, allow_destroy: :true
end
I'm trying to create a form for 'Member' using simple_form and having trouble displaying an association where it display the organization as below instead of the id, or organization_name. Am I missing something here? How should I go about this?
**Organization:0x0000000485cf88
Organization:0x0000000485c948
Organization:0x0000000485c358**
class Organization < ActiveRecord::Base
has_many :members
attr_accessible :organization_name
end
class Member < ActiveRecord::Base
belongs_to :organization
attr_accessible :active, :email, :first_name, :last_name, :role
end
<%= f.input :first_name %>
<%= f.input :last_name %>
<%= f.input :role %>
<%= f.input :email %>
<%= f.input :active %>
<%= f.association :organization %>
<%= f.button :submit %>
Thanks.
Cheers,
Azren
looks like Organization model doesn't have any of these fields: [ :to_label, :name, :title, :to_s ] so SimpleForm can't detect a default label and value methods for collection. I think you should pass it manually.
add to_label function to your Organization class as shown below
class Organization < ActiveRecord::Base
has_many :members
attr_accessible :organization_name
def to_label
"#{organization_name}"
end
end
refered
Simple form association custom label name