I need some conceptual help:
Assume your Users are essentially a business. You have Employees and you have Staff Positions. Essentially, one employee could hold multiple positions and one position could hold multiple employees.
My have_many :through is working between the Employees and the Positions through a join table Staffization. However, my edit form for the employee is returning ALL the Positions as checkboxes for the whole app, not just the ones for this particular User. And, none are being saved when I submit an update.
Do I need to do something different with my associations, or is there a better way to narrow the data in the forms?
My models:
class User < ActiveRecord::Base
has_many :employees, :dependent => :destroy
has_many :positions, :dependent => :destroy
class Employee < ActiveRecord::Base
belongs_to :user
has_many :positions, :through => :staffizations
has_many :staffizations, :dependent => :destroy
class Position < ActiveRecord::Base
belongs_to :user
has_many :employees, :through => :staffizations
has_many :staffizations, :dependent => :destroy
class Staffization < ActiveRecord::Base
belongs_to :employee
belongs_to :position
My employee edit fields form is set up to return checkboxes for the possible positions the employee could hold but is return all the positions in the whole app and is not updating the data when I hit submit:
- Position.all.each do |position|
= check_box_tag :position_ids, position.position_name, #employee.positions.include?(position), :name => 'employee[position_ids][]'
= label_tag :position_ids, position.position_name
My employees controller update def added the line for the have_many :through association. Is this where I should narrow the return down to the current signed in user's employees and positions?
#employee.attributes = {'position_ids' => []}.merge(params[:employee] || {})
First, shouldn't you be using :
class Employee
has_and_belongs_to_many :positions
end
class Position
has_and_belongs_to_many :employees
end
then, you could narrow the available positions with :
Position.where(:user_id => #employee.user_id).each # etc.
you could even make a scope for it:
class Position
def available_for_employee employee
where(:user_id => employee.user_id)
end
end
... and then use this in a helper that generates your checkboxes
def position_checkboxes_for_employee employee
Position.available_for_employee(employee).each do |position|
= check_box_tag :position_ids, position.position_name, #employee.positions.include?(position), :name => 'employee[position_ids][]'
= label_tag :position_ids, position.position_name
end
end
returning ALL the positions as checkboxes is exactly what you'd want, no?
what if a employee changes positions? you'd need that checkbox then, not only the checked ones..
Thanks to a friend, since my have_many through between my employees and positions belongs to the business. I needed to add the attr_accessible position_ids and attr_accessible employee_ids to the respective models. In addition, in my employee view field, I needed to add the options so that my call for positions only calls those positions associated with this business, like so:
- Position.find_all_by_user_id(#employee.user_id).each do |position|
= check_box_tag :position_ids, position.id, #employee.positions.include?(position), :name => 'employee[position_ids][]'
= label_tag :position_ids, position.position_title
Related
I am stuck struggling with rich join tables in Rails 5 and need help getting on track. The app I'm writing will help me track which of our company's suppliers carry which brands of products. Because I also need to track whether each supplier is authorized or unauthorized for each of the brands they sell, and whether they carry those brands in stock, I thought the best approach was to use a join table and store the attributes there. In other words:
Suppliers <---> Lines <---> Brands
Beyond the foreign key references for a Supplier and a Brand, the Line record also has two boolean attributes: .is_authorized and .carries_stock.
My models:
/models/supplier.rb
class Supplier < ApplicationRecord
has_many :lines, :dependent => :destroy
has_many :brands, :through => :lines
accepts_nested_attributes_for :lines
end
/models/brand.rb
class Brand < ApplicationRecord
has_many :lines, :dependent => :destroy
has_many :suppliers, :through => :lines
end
/models/line.rb
class Line < ApplicationRecord
belongs_to :supplier
belongs_to :brand
validates_presence_of :supplier
validates_presence_of :brand
end
I've been able to set up the controller and supplier edit form to allow creating records in the Lines table, but have no clue how to allow the users to edit the .is_authorized and .carries_stock attributes. I have been able to get the create/edit supplier form to work by adding the following snippet:
/views/suppliers/_form.html.erb
<h4>Brands</h4>
<%= form.collection_check_boxes(:brand_ids, Brand.all, :id, :name) do |b| %>
<%= b.label class:"label-checkbox" do%>
<%= b.check_box + b.text%>
<%end%>
<br />
<% end %>
The form looks like this now but doesn't allow me to edit the rich attributes .is_authorized and .carries_stock. I'd like the form to look something more like this. Where do I go from here?
Thanks!!!
I have a Rails 4 app, with models Challenge and ChallengeList. It's a many-to-many relationship, so I also have a join table with model ChallengeListsChallenge. I defined this last model because I want my ChallengeLists to be ordered lists, and so used it to exploit acts_as_list:
class ChallengeList < ActiveRecord::Base
has_many :challenge_lists_challenges, :dependent => :destroy
has_many :challenges, :through => :challenge_lists_challenges
accepts_nested_attributes_for :challenges
end
class ChallengeListsChallenge < ActiveRecord::Base
default_scope :order => 'position'
belongs_to :challenge
belongs_to :challenge_list
acts_as_list :scope => :challenge_list
end
This works fine.
In my HTML, I have a form that allows the user to define a new ChallengeList. It has a nested form for Challenges:
= f.fields_for :challenges do |challenge_builder|
.field
= challenge_builder.text_field :description
But I would also like the user to be able to change the position. So I thought I'd be smart, add a field for position:
= challenge_builder.text_field :position
Of course, this doesn't work, because 'position' is set on join items, not Challenge items.
Having a nested form for ChallengeListsChallenges would give me access to the position, but is not cool because:
I need a reference to my ChallengeList id (which is not insurmountable, but not pretty either)
I can only reference existing Challenge ids
So what can I do?
Like in this question:
Set up model dependencies like so:
class ChallengeList < ActiveRecord::Base
has_many :challenge_lists_challenges, :dependent => :destroy
has_many :challenges, :through => :challenge_lists_challenges
accepts_nested_attributes_for :challenge_lists
end
class ChallengeListsChallenge < ActiveRecord::Base
default_scope :order => 'position'
belongs_to :challenge
belongs_to :challenge_list
acts_as_list :scope => :challenge_list
accepts_nested_attributes_for :challenges
end
And a doubly nested form like so:
= form_for #challenge_list do |f|
= f.fields_for :challenge_lists_challenges do |links_form|
.field
= links_form.number_field :position
%br/
= links_form.fields_for :challenge do |challenge_form|
.field
= challenge_form.text_field :description
= challenge_form.text_field :id
And it should work.
I have a model "Trip" and I want to be able to have only certain users in "Group" create "comments".
When I first created the trip model, I had it set so that only one user can edit it. Now, I want to be able to invite other users to edit it as well. The part that is tripping me up (pun intended) right now is that I have both trip belong_to :user (the user who created it) and trip has_many :users, :through => :group.
Questions:
Is this allowed per Rails convention?
Based on my model, group will have both user_id and trip_id. Is this the best way to approach this problem? That is, should there be a new record in the database for every user I invite to the group?
Thanks.
user.rb
class User < ActiveRecord::Base
has_many :trips, :through => :groups
has_many :trips, :dependent => :destroy
has_many :groups
has_many :comments, :dependent => :destroy
end
group.rb
class Group < ActiveRecord::Base
belongs_to :trip
belongs_to :user
end
trip.rb
class Trip < ActiveRecord::Base
belongs_to :user
belongs_to :traveldeal
has_many :groups
has_many :users, :through => :groups
end
comment.rb
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :commentable, :polymorphic => true
end
view (show.html.erb)
<% unless #user.trips.empty? %>
<% #user.trips.each do |trip| %>
<!-- Content here -->
<% end %>
<% end %>
Normal Rails convention would have been to call the Group model something like TripPerson to specify the two tables that it was joining, but these join tables are a natural byproduct of relational databases. You'll have to continue creating a new Group object for every person invited to the trip.
Having some challenges, need to keep track of the courses an Employee have taken. This is what i have these tables so far
Course: course_id,name,category_of_course...#holds Course related details
Employee: employee_id, name...#holds Employee details
progress:course_id,employee_id, status ...#holds which course have been
taken and by whom
in My Models, i have this relationships:
Employee: has_many :courses
Please how do i populate a Select List with the Courses that an Employee have not taken(assuming after registering for a course, it's flagged as taken). Im using rails 3.0.9 with MySql.
Thank You
You need to define
belongs_to :employee
belongs_to :course
(in your progress model)
You can then define
#Employee
has_many :progresses
has_many :courses, :through => :progresses
#Course
has_many :progresses
has_many :employees, :through => :progresses
The select list will be:
= form_for #something do |f|
= f.select :course_id, Course.all.select{|x| not #employee.courses.include?(x)}.collect{|x|[x.name,x.id]} #Ideally this logic should reside in the model.
Right now I'm building a social media app, where i want an user to have a rating per category, how would the association go? The way it needs to be setup it's Each user will have a different rating in each category.
I'm think that
belongs_to :user
belongs_to :category
in the UserCategoryRating model.
and
has_many :user_category_ratings, through => :category
on the User model, Is this the correct approach?
The UserCategoryRating table has the User_id column, Category_id column, and the rating column, that updates each time an user gets votes (The rating it's just the AVG between votes and the score based on 1-5)
UPDATE: If I'm understanding you correctly, here is a diagram of the simple design you'd like:
And this would be the basic skeleton of your classes:
class User < ActiveRecord::Base
has_many :ratings
# has_many :categories, :through => :ratings
end
class Category < ActiveRecord::Base
has_many :ratings
# has_many :users, :through => :ratings
end
class Rating < ActiveRecord::Base
belongs_to :user
belongs_to :category
validates_uniqueness_of :user_id, :scope => [:category_id]
end
Will allow for these query:
#category_ratings_by_user = Rating.where("ratings.user_id = ? AND ratings.category_id = ?", user_id, category_id)
#specific_rating = user.ratings.where("ratings.category_id = ?", category_id)
# make nice model methods, you know the deal
# ... if you added the has_many :through,
#john = User.find_by_name("john")
# Two ways to collect all categories that john's ratings belong to:
#johns_categories_1 = #john.ratings.collect { |rating| rating.category }
#johns_categories_2 = #john.categories
#categories_john_likes = #john.categories.where("categories.rating >= ?", 7)
I'm just unsure as to why you want this has_many, :through (this doesn't seem like a many to many -- a rating only belongs to one user, correct?).
I will use the following data model:
class User
has_many :user_categories
has_many :categories, :through => :user_categories
end
class UserCategory
belongs_to :user
belongs_to :category
# this model stores the average score also.
end
class Category
has_many :user_categories
has_many :users, :through => :user_categories
end
Now when you want to update the score of a user for a category
uc = u.user_categories.find_by_category_id(id)
uc.score = score
uc.save