I am trying to create two has many relations to the same destination tables but I am unable to override the default method name rails creates when defining the association.
The following is the case:
class User < ApplicationRecord
has_many :conference_attendees, dependent: :destroy
has_many :conference_organizers, dependent: :destroy
has_many :conferences, through: :conference_attendees, class_name: 'attending', dependent: :destroy
has_many :conferences, through: :conference_organizers, source: :conference, dependent: :destroy
class ConferenceOrganizer < ApplicationRecord
alias_attribute :organizers, :users
belongs_to :conference
belongs_to :user
end
class ConferenceAttendee < ApplicationRecord
belongs_to :conference
belongs_to :user
end
class Conference < ApplicationRecord
has_many :conference_attendees, dependent: :destroy
has_many :conference_organizers, dependent: :destroy
has_many :users, through: :conference_attendees, dependent: :destroy
has_many :organizers, through: :conference_organizers, source: :user, dependent: :destroy
I am trying to access all the conferences that a user attended and then all conferences that a user organized using something like following:
User.find(id: <id>).organizing
User.find(id: <id>).attending
but I am unable to and
User.find(id: <id>).conferences
defaults to organizing conferences. How do I access attending conferences?
Since you are doing a join on the same two tables it might be cleaner to do one join table and add a field called status to distinguish organizer from attendee. That way you can add other status values such as "presenter".
set up the table rails g model Registration user:references conference:references status:string; rake db:migrate
Set up the model associations:
# app/models/user.rb
has_many :registrations, dependent: :destroy
# app/models/conference.rb
has_many :registrations, dependent: :destroy
# app/models/registration.rb
belongs_to :user
belongs_to :conference
scope :attendees, -> { where( status: "Attendee") }
scope :organizers, -> { where( status: "Organizer") }
Then to show the attendees and organizers on the conference show page:
# app/controllers/conferences_controller.rb
def show
#conference = Conference.find(params[:id])
#attendee_registrations = #conference.registrations.attendees
#organizer_registrations = #conference.registrations.organizers
end
# app/views/conferences/show.html.erb
<h3>Organizers</h3>
<% #organizer_registrations.each do |registration| %>
<li><%= link_to(registration.user.name, registration.user) %></li>
<% end %>
<h3>Attendees</h3>
<% #attendee_registrations.each do |registration| %>
<li><%= link_to(registration.user.name, registration.user) %></li>
<% end %>
Then to show the conferences on the user's show page:
# app/controllers/users_controller.rb
def show
#user = User.find(params[:id])
#attending_registrations = #user.registrations.attendees
#organizing_registrations = #user.registrations.organizers
end
# app/views/users/show.html.erb
<h3>Conferences Organizing</h3>
<% #organizing_registrations.each do |registration| %>
<li><%= link_to(registration.conference.name, registration.conference) %><br>
Date: <%= registration.conference.date %></li>
<% end %>
<h3>Conferences Attending</h3>
<% #attending_registrations.each do |registration| %>
<li><%= link_to(registration.conference.name, registration.conference) %><br>
Date: <%= registration.conference.date %></li>
<% end %>
If you want two join tables on Users and Conferences you can set it up this way.
# app/models/user.rb
has_many :conference_attendees, dependent: :destroy
has_many :conference_organizers, dependent: :destroy
has_many :attending, through: :conference_attendees, source: :conference
has_many :organizing, through: :conference_organizers, source: :conference
# app/models/conference.rb
has_many :conference_attendees, dependent: :destroy
has_many :conference_organizers, dependent: :destroy
has_many :attendees, through: :conference_attendees, source: :user
has_many :organizers, through: :conference_organizers, source: :user
# app/models/conference_attendee.rb
belongs_to :user
belongs_to :conference
# app/models/conference_organizer.rb
belongs_to :user
belongs_to :conference
Then to show the attendees and organizers on the conference show page:
# app/controllers/conferences_controller.rb
def show
#conference = Conference.find(params[:id])
#attendees = #conference.attendees
#organizers = #conference.organizers
end
# app/views/conferences/show.html.erb
<h3>Organizers</h3>
<% #organizers.each do |user| %>
<li><%= user.name %></li>
<% end %>
<h3>Attendees</h3>
<% #attendees.each do |user| %>
<li><%= user.name %></li>
<% end %>
Then to show the conferences on the user's show page:
# app/controllers/users_controller.rb
def show
#user = User.find(params[:id])
#attending = #user.attending
#organizing = #user.organizing
end
# app/views/users/show.html.erb
<h3>Conferences Organizing</h3>
<% #organizing.each do |conference| %>
<li><%= link_to(conference.name, conference) %><br> Date: <%= conference.date %></li>
<% end %>
<h3>Conferences Attending</h3>
<% #attending.each do |conference| %>
<li><%= link_to(conference.name, conference) %><br> Date: <%= conference.date %></li>
<% end %>
That being said it may be cleaner to use one join table rather than two. I'll put that in a separate answer.
Related
I have 3 Models
class User < ActiveRecord::Base
has_many :teams, :through => :team_memberships
has_many :team_memberships
end
class Teams < ActiveRecord::Base
has_many :users, :through => :team_memberships
has_many :team_memberships
has_many :clubs, :through => :club_memberships
has_many :club_memberships
end
class Clubs < ActiveRecord::Base
has_many :teams, :through => :club_memberships
has_many :club_memberships
end
I want to be able to get a unique list of clubs that the user is a member of. If I have the following:
#teams = User.last.teams
How can I get a list of clubs that these teams are members of. If there are any duplicates I would like to only show them once in the list.
Currently if I do:
<% #user.teams.each do |t| %>
<% t.clubs.each do |c| %>
<%= link_to c.name, c %>
<% end %>
<% end %>
I obviously get a complete list but I want to remove the duplicates. Can anyone offer a fix?
Looks like I can just set up a relationship like so:
class User < ActiveRecord::Base
has_many :clubs, -> { uniq }, :through => :teams
end
and then reference:
<% #user.clubs.each do |c| %>
<%= c.name %>
<% end %>
Please let me know if there is a better way!
I have a model relationship set up like this:
# User model
class User < ActiveRecord::Base
belongs_to :company
has_many :answers
# groups
has_many :group_memberships
has_many :group_questions, through: :groups, source: :questions
has_many :groups, through: :group_memberships
# question
has_many :question_participants, as: :questionable
has_many :questions, through: :question_participants
# questions created by admin
class Question < ActiveRecord::Base
belongs_to :company
has_many :question_participants
has_many :answers
has_many :users, through: :question_participants,
source: :questionable, source_type: 'User'
has_many :groups, through: :question_participants,
source: :questionable, source_type: 'Group'
has_many :companies, through: :question_participants,
source: :questionable, source_type: 'Company'
end
# user answers to questions
class Answer < ActiveRecord::Base
belongs_to :user
belongs_to :question
end
now my answer stores user_id, reply (their answer) and question id.
What I'd like to be able to create now is a form that allows a user to answer all the questions asked to them, and submit the answers.
I've setup my form like this on the view file (answers#new):
<%= form_for #answer do |f| %>
<% current_user.all_questions.each do |question| %>
<%= f.hidden_field :question_id, value: question.id %>
<p><%= question.name %>
<%= f.text_field :reply %>
<% end %>
<% end %>
which doesn't work, and I get why - issue is i don't know how to make it work with multiple save.
I hope I got your problem. Here is what I suggest:
<%= form_for #answer do |f| %>
<% current_user.all_questions.each do |question| %>
<%= hidden_field_tag 'questions[][id]', question.id %>
<p><%= question.name %>
<%= text_field_tag 'questions[][reply]' %>
<% end %>
<% end %>
Now in the controller action you can access params[:questions] and you'd get smth like this: [{"id"=>"1", "reply"=>"some text 1"}, {"id"=>"2", "reply"=>"some text 2"}]:
# your_controller.rb
def create_answers
answers = params[:questions].map do |question|
current_user.answers.create(question_id: question[:id], reply: question[:reply])
end
if answers.any(&:invalid?)
flash[:error] = 'Some answers were not accepted'
redirect_to :back
else
redirect_to home_path
end
end
I have five models:
class User < ActiveRecord::Base
has_many :administrations
has_many :calendars, through: :administrations
has_many :comments
end
class Calendar < ActiveRecord::Base
has_many :administrations
has_many :users, through: :administrations
has_many :posts
end
class Administration < ActiveRecord::Base
belongs_to :user
belongs_to :calendar
end
class Post < ActiveRecord::Base
belongs_to :calendar
end
class Comment < ActiveRecord::Base
belongs_to :post
belongs_to :user
end
The comment table has the following columns: id, post_id, user_id and body.
In different views, for instance in the show.html.erb post view, I need to display the relevant comments with the first name of the user who posted the comment.
In other words, I am trying to retrieve user.first_name from comment.user_id.
To achieve this, I defined the following method in the comment.rb file:
def self.user_first_name
User.find(id: '#{comment.user_id}').first_name
end
and then I updated the show.html.erb post view as follows:
<h3>Comments</h3>
<% #post.comments.each do |comment| %>
<p>
<strong><%= comment.user_first_name %></strong>
<%= comment.body %>
</p>
<% end %>
When I do that, I get the following error:
NoMethodError in Posts#show
undefined method `user_first_name' for #<Comment:0x007fc510b67380>
<% #post.comments.each do |comment| %>
<p>
<strong><%= comment.user_first_name %></strong>
<%= comment.body %>
</p>
<% end %>
I don't really understand Why I get an error related to Posts#show.
Any idea how to fix this?
Replace:
comment.rb
def self.user_first_name
User.find(id: '#{comment.user_id}').first_name
end
with:
comment.rb
delegate :first_name, to: :user, prefix: true
If you do this, you can just make the same call comment.user_first_name and it will give you the user's first name. Add , allow_nil: true if you don't want it to break if the user doesn't have a first_name.
You also might want to add:
has_many :comments
user.rb
class User < ActiveRecord::Base
has_many :administrations
has_many :calendars, through: :administrations
has_many :comments
end
I am trying to display the number of UserLesson.where(user_id: current_user_id) in the provided view (profiles_controller.rb). At the moment it displays the total UserLesson and not to individual user.
Here is my view:
<% #user.lectures.each do |lecture| %>
<div class="col-md-4 margin-s mb-60">
<div class="lecture-box">
<%= image_tag lecture.picture.url(:medium) %>
<%= lecture.lessons.size %>
<%= lecture.lessons.total_lesson %> #SHOULD BE HERE
<p class="pad5"><%= truncate(lecture.description, length: 80) %> </p>
<%= link_to "Start Now", lecture, class: "btn btn-primary" %>
</div> <!-- .lecture-box -->
</div> <!-- .col-md-4 -->
<% end %>
Here is my lesson.rb:
class Lesson < ActiveRecord::Base
has_one :lecture, through: :chapter
belongs_to :chapter
has_many :user_lessons
def self.total_lesson
Lesson.joins(:user_lessons).size
end
end
Other Models:
class UserLesson < ActiveRecord::Base
belongs_to :user
belongs_to :lesson
# validates_uniqueness_of :user_lesson, :scope => [:user, :lesson]
end
class Lesson < ActiveRecord::Base
has_one :lecture, through: :chapter
belongs_to :chapter
end
class User < ActiveRecord::Base
has_many :enrollments
has_many :user_lessons
has_many :lectures, through: :enrollments
accepts_nested_attributes_for :enrollments
end
class Enrollment < ActiveRecord::Base
belongs_to :user
belongs_to :lecture
validates :lecture, uniqueness: { scope: :user, message: "should happen once per user" }
end
class Lecture < ActiveRecord::Base
belongs_to :category
has_many :lessons, through: :chapters, dependent: :destroy
has_many :chapters
belongs_to :teacher
# For course user relationship
has_many :enrollments
has_many :users, through: :enrollments
accepts_nested_attributes_for :enrollments
accepts_nested_attributes_for :chapters
end
class Chapter < ActiveRecord::Base
has_many :lessons
belongs_to :lecture
accepts_nested_attributes_for :lessons
end
To find the number of lessons belonging to a lecture in which the current user is related you can do this
<%= lecture.lessons.select{ |l| l.users.inculde? current_user }.count %>
but you have to add this to Lesson.rb:
has_many :users, through: :user_lessons
As you have #user in your view (which is the current_user), so you can just call the following in your view to get the total number of lessons for this user:
Lesson.joins(:user_lessons).where('user_lessons.user_id = ?', #user.id).count
To get the total number of lessons in this lecture for this user:
Lesson.joins(:user_lessons).joins(:lectures).where('user_lessons.user_id = ? AND lectures.id = ?', #user.id, lecture.id).count
where lecture is your local variable in your view file.
You should be able to call this directly from your view to get the desired count.
I have two models "Stores" and "Vendors". I created a separate join model called "Partnerships" so a store can have many vendors and the Vendor can have many stores. When the user is logged in they are affiliated to either a store or vendor. I want them to be able to create partnerships. I think I have the model down based on my research, but I can't seem to get the controller right. Most of the online examples only show the models not the controller.
class Store < ActiveRecord::Base
attr_accessible :industry, :name
has_many :users
has_many :workorders
has_many :locations
has_many :partnerships
has_many :vendors, :through => :partnerships
class Vendor < ActiveRecord::Base
attr_accessible :industry, :name
has_many :users
has_many :workorders
has_many :locations
has_many :partnerships
has_many :stores, :through => :partnerships
class Partnership < ActiveRecord::Base
belongs_to :store
belongs_to :vendor
attr_accessible :store_id, :vendor_id, :store, :vendor
This is my current partnerships_controller#new where I get a type mismatch error during my test.
if params[:store_id]
#store = Store.where(:id => params[:store_id])
#partnership = Partnership.new(store: #store)
else
flash[:error] = "Store partnership required"
end
Here is my new.html.erb for Partnerships:
<% if flash[:error] %>
Not found.
<% else %>
<% if current_user.affiliation == 'Vendor' %>
<div class="page-header">
<h1> <%= #store.name %></h1>
</div>
<% else %>
<div class="page-header">
<h1> <%= #vendor.name %></h1>
</div>
<% end %>
<% end %>
My User model includes an affiliation field that is either "Store" or "Vendor" and also a company_id field.
What would my controller look like to create a new partnership if I am a user whose affiliation = 'Store'? Would I do it in the partnership controller?