Polymorphic Associations and signup forms Rails - html

I have a User table in Rails and it has 2 user types. I associated them with polymorphic associations, my models are:
class User < ActiveRecord::Base
belongs_to :owner, polymorphic: true
class Buyer < ActiveRecord::Base
has_one :user, as: :owner, dependent: :destroy
accepts_nested_attributes_for :user
class Seller < ActiveRecord::Base
has_one :user, as: :owner, dependent: :destroy
accepts_nested_attributes_for :user
I need a registration form in HTML for new users and automatically specify their type (each user type has their own registration link)
How do I manage the controllers and HTML form to do this? The user is going to fill the form with information for the User and Buyer or Seller model.
Thank you

You need 2 routes, one for buyer and another for seller. And then you can use Rail's form helpers:
<%= form_for :buyer do |f| %>
<%= f.fields_for :user %>
[your user fields here]
<% end %>
<% end %>
The form is analogous for the seller.

Related

uninitialized constant User::follow Extracted source (around line #28):

i have an error in my user.rb model (around line #28):
27def following?(user)
28 following.include?(user)
29end
Any idea what I could be doing wrong here?
Showing C:/instagramm/instagram-clone/app/views/accounts/profile.html.erb where line #11 raised:
my profile.html.erb :
<% if #users.image.present %>
<%= image_tag #users.image %>
<% end %>
<strong><h1><%= #users.full_name %></h1></strong>
<% if user_signed_in? && #user == current_user %>
<%= link_to"Edit Profile", edit_user_registration_path(#user) %>
<% if current_user.following?(#user) %>
<%= link_to"Unfollow", follows_path(user_id: #user.id), method: :delete %>
<% else %>
<%= link_to"Follow", follows_path(user_id: #user.id) %>
<% end %>
<% end %>
<div> <%= #users.posts.count %> Posts </div>
<p><%= #users.full_name %></p>
<p><%= #users.description %></p>
<p><%= link_to 'User Website', #users.website if #users.website.present? %></p>
<%= #posts.each do |post|%>
<%= image_tag post.image %>
<% end %>
my model : follow.rb
class Follow < ApplicationRecord
belongs_to :follower, class_name: 'user'
belongs_to :followed, class_name: 'user'
validates :follower_id, presence: true
validates :followed_id, presence: true
end
and this is my user.rb model : the error is around(#line28) in def following?(user)
class User < ApplicationRecord
has_many :posts
validates :username, presence: true
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_one_attached :image
has_many :active_follows, class_name: "follow", foreign_key: "follower_id", dependent: :destroy
has_many :passive_follows, class_name: "follow", foreign_key: "followed_id", dependent: :destroy
has_many :following, through: :active_follows, source: :followed
has_many :followers, through: :passive_follows, source: :follower
def follow(user)
active_follows.create(followed_id: user.id)
end
def unfollow(user)
active_follows.find_by(followed_id: user.id).destroy
end
def following?(user)
following.include?(user)
end
def full_name
"#{first_name} #{last_name}"
end
end
Rails assumes that association points to a class with matching name, so in this case your following association will search for Following class.
Obviously it is not what you need here - having a quick guess by the code structure that you expect following to return a collection of Users, so you need to tell that to your association:
has_many :following, through: :active_follows, source: :followed, class_name: 'User'
It is also important to use correct class names given to class_name option. It has to match the name of the ActiveRecord class exactly, so it must be "Follow" not "follow" and, similarly, "User" not "user"
You already got response from #BroiStase you are using incorrect name of classes in your code. Please change your Follow.rb
class Follow < ApplicationRecord
belongs_to :follower, class_name: 'User'
belongs_to :followed, class_name: 'User'
validates :follower_id, presence: true
validates :followed_id, presence: true
end
In your User.rb following you have to do following changes.
class User < ApplicationRecord
has_many :posts
validates :username, presence: true
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_one_attached :image
has_many :active_follows, class_name: "Follow", foreign_key: "follower_id", dependent: :destroy
has_many :passive_follows, class_name: "Follow", foreign_key: "followed_id", dependent: :destroy
has_many :following, through: :active_follows, source: :followed
has_many :followers, through: :passive_follows, source: :follower
def follow(user)
active_follows.create(followed_id: user.id)
end
def unfollow(user)
active_follows.find_by(followed_id: user.id).destroy
end
def following?(user)
following.include?(user)
end
def full_name
"#{first_name} #{last_name}"
end
end
Please when you code avoid any extra spaces, line breaks and give proper 2 space indentions it will help you to understand code better. If still error please share error message also.

Rails - Having multiple 'has_many through 'associations on the same model

I am working on a rails app that registers campers for a camp. First you sign up using your name, email, etc. Once your profile is made, you can register for a camp. If the camp is not already full, then you are immediately enrolled. If it is full, then you are put on a waitlist. Right now I have 4 models: Campers (name, email, etc.), Camps (name, location, etc.), Enrollments, and Waitlists.
The idea is to have a camper be able to register to many camps, and obviously a camp having many campers enrolled or waitlisted in it. Here are my classes:
# camper.rb
has_many :enrolled_in, :class_name => 'Camps', through: :enrollments, dependent: :destroy
has_many :waitlisted_in, :class_name => 'Camps', through: :waitlists, dependent: :destroy
# camp.rb
has_many :enrolled_campers, :class_name => 'Camper', through: :enrollments
has_many :waitlisted_campers, :class_name => 'Camper', through: :waitlists
I'm having trouble with accessing these models through the views. Here is what show.html.erb looks like:
<!-- Listing camps -->
<h2>Camps</h2>
<p>
<strong>Name:</strong>
<%= #camper.enrolled_in.name %> <!-- This is where I get the error -->
</p>
<!-- Adding camps -->
<h2>Add a camp:</h2>
<%= form_with(model: [#camper, #camper.enrolled_in.build ]) do |form| %>
<p>
<%= form.label :name %><br>
<%= form.text_field :name %>
</p>
<p>
<%= form.submit %>
</p>
<% end %>
But I'm getting the following error:
ActiveRecord::HasManyThroughSourceAssociationNotFoundError in Campers#show
Could not find the source association(s) "enrolled_in" or :enrolled_in in model Enrollment. Try 'has_many :enrolled_in, :through => :enrollments, :source => '. Is it one of camp or camper?
And I honestly can't tell what's going wrong. I'm fairly new to databases and rails, so go easy on me.
Look to direction of HABTM associations.
This will make your code cleaner.
You will have :after_add and :after_destroy actions that will always track model changes (even direct foreign key inserting, unlike in same named has_many callbacks.)
So.
class Camper
has_and_belongs_to_many :waitlists, after_add: :check_camp_ready_to_start_as_example
has_and_belongs_to_many :enrolllists
end
class Waitlist
belongs_to :camp
has_and_belongs_to_many :campers
end
class Enrolllist
belongs_to :camp
has_and_belongs_to_many :campers
end
class Campl
has_many :enrolllists
has_many :waitlists
end
How to create such migrations (need to create join tables), you can read here

undefined method `cliq_requests' for nil:NilClass

I keep getting this annoying error consistently and I cannot solve it. I recently posted a question on the same topic and got no productive help.
I want users to request to join a group. Cliqs = Groups. All of my console tests seem correct, but I cannot seem to find a solution to my problem. The association is showing up, but I can't seem to get the update/accept method to run.
This is driving me crazy! How do I fix this?
Here is my code:
My Models:
class User < ActiveRecord::Base
has_many :uploads
has_one :owned_cliq, foreign_key: 'owner_id', class_name: 'Cliq', dependent: :destroy
has_many :cliq_memberships, dependent: :destroy
has_many :cliqs, through: :cliq_memberships
has_many :cliq_requests, dependent: :destroy
...
end
class Cliq < ActiveRecord::Base
belongs_to :owner, class_name: 'User'
has_many :cliq_memberships, dependent: :destroy
has_many :members, through: :cliq_memberships, source: :user
has_many :cliq_requests, dependent: :destroy #cliq_request_sender
has_many :pending_members, through: :cliq_requests, source: :user, foreign_key: 'user_id'
end
class CliqRequest < ActiveRecord::Base
#from
belongs_to :user
#to
belongs_to :cliq
#validate :not_member
#validate :not_pending
def accept
cliq.members << pending_member
destroy
end
end
My controller:
class CliqRequestsController < ApplicationController
def index
#incoming
##cliq_requests_received = CliqRequest.where(cliq: cliq)
#outgoing
##cliq_requests_sent = current_user.cliq_requests
end
def show
end
def create
cliq = Cliq.find_by(params[:id])
#cliq_request = current_user.cliq_requests.new(cliq: cliq)
if #cliq_request.save
redirect_to current_user #change to cliqs/cliq path later
else
redirect_to cliq_path
end
end
def update
#cliq = Cliq.find_by(id: params[:cliq_id])
#cliq_request = #cliq.cliq_requests.find_by(id: params[:id])
#cliq_request.accept
end
def destroy
#cliq_request.destroy
end
end
My View:
<h1><%= #cliq.name %></h1>
<%= link_to 'Request to join Cliq', '/cliqs/:cliq_id/cliq_requests', :method => :post %>
<% #cliq_members.each do |cliq_member| %>
<ul><%= link_to cliq_member.username, user_path(cliq_member) %></ul>
<% end %>
<% if #current_user = #cliq.owner %>
<% #cliq.pending_members.each do |pending_member| %>
<ul><%= link_to pending_member.username, user_path %>
<%= link_to "Accept", "/cliqs/:cliq_id/cliq_requests/:id/", :method => :put %>
<%= link_to "Deny", "/cliqs/:cliq_id/cliq_requests/:id/", :method => :delete %>
</ul>
<% end %>
<% end %>
My Routes:
resources :cliqs do
resources :cliq_requests
end
These lines appear malformed:
<%= link_to 'Request to join Cliq', '/cliqs/:cliq_id/cliq_requests', :method => :post %>
<%= link_to "Accept", "/cliqs/:cliq_id/cliq_requests/:id/", :method => :put %>
<%= link_to "Deny", "/cliqs/:cliq_id/cliq_requests/:id/", :method => :delete %>
I recommend you use path helpers [e.g. cliq_cliq_request_path(cliq, cliq_request) if you are using resourceful routing]. You can use rake routes for help. If you are seeing things like :cliq_id and and :id in your development.log or test.log as part of the URLs that are hit, those should instead be numbers. You can also interpolate the strings yourself (e.g. "/cliqs/#{cliq_id}/cliq_requests/#{cliq_request.id}") but this is usually more typing and certainly more fragile over time.
One of your problems may be that you are looping through a list of pending member names, which doesn't have all the data you need to form the link correctly. So your update action may be working fine, but you may not be passing it the right data.
Also this line:
if #current_user = #cliq.owner
is an assignment, and so will always return true. Presumably you mean ==

Rails survey style application - Show all answers on option

I'm a new guy to ruby on rails and working on my first in-depth application. It has four tables: Questions, Options, Answers and Users. There's a list of questions and a user can vote for a unique option (stored in the Answers join table), I'm trying to get my head around table associations.
This is how I've setup my individual RB files:
class Question < ActiveRecord::Base
has_many :options
has_many :answers, :through => :options
end
class Option < ActiveRecord::Base
belongs_to :question
has_many :answers
end
class Answer < ActiveRecord::Base
belongs_to :user
belongs_to :question
belongs_to :option
end
class User < ActiveRecord::Base
has_many :answers
has_many :questions, :through => :answers
end
My questions controller is setup like this to include the options table:
#questions = Question.includes(:options).all
and the table body in my index.html.erb file:
<tbody>
<% #questions.each do |question| %>
<tr class="<%= cycle('lineOdd', 'lineEven') %>">
<td><%= question.question_text %></td>
<td><%= link_to 'Show', question %></td>
<td><%= link_to 'Edit', edit_question_path(question) %></td>
<td><%= link_to 'Destroy', question, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% question.options.each do |option_text| %>
<tr class="backgroundColor1">
<td class="optionCell"> <%= option_text.option_text %> </td>
</tr>
<% end %>
<% end %>
</tbody>
In the Question class I've used 'has_many :answers, :through => :options' - is this the correct way to go about this and how would I output the total number of votes in a table row below the associated option.
Do I need to add to or change the question controller code?
This is my first post, sorry if I'm not informative enough!
Thanks
Lets start by fixing up the relations a bit:
class Question < ActiveRecord::Base
has_many :options
has_many :answers
has_many :users, through: :answers
end
There is nothing technically wrong with has_many :answers, :through => :options but since there is a direct relation through answers.question_id we don't need to go through the options table for the relation.
Displaying the count
If we simply did:
<td class="optionCell"><%= option.answers.count %></td>
This would create a nasty n+1 query to fetch the count of the answers for each option. So what we want to do is create a counter cache which stores a tally on the options table.
Lets start by creating a migration to add the column:
rails g migration AddAnswerCounterCacheToOptions answers_count:integer
rake db:migrate
Then we tell ActiveRecord to update the tally when we create associated records, this looks a bit strange since the counter_cache: true declaration is on the belongs_to side while the column is on the other but thats just how AR works.
class Option < ActiveRecord::Base
belongs_to :question
has_many :answers
end
class Answer < ActiveRecord::Base
belongs_to :user
belongs_to :question
belongs_to :option, counter_cache: true
end
There is a little snag here. Since we may already have records we need to make sure they have correct counters. You can do this from the console but in the long run it is a good idea to create a rake task.
Option.find_each { |option| Option.reset_counters(option.id, :answers) }
This might take a bit of time since it needs to pull each Option and update the count.
Now we can display the tally like so:
<% question.options.each do |option| %>
<tr class="backgroundColor1">
<td class="optionCell"><%= option.option_text %></td>
<td class="optionCell"><%= option.answers.size %></td>
</tr>
<% end %>
.size is smart enough to use our counter cache column, but will fall back to querying the count which is a good thing for tests.

Associating a models using foreign keys

My goal is to have a setup where Users create Grants as funders and then other users are matched with grants as reachers. I've been playing around with a few options for the model set up such as:
class Grant < ActiveRecord::Base
belongs_to :funder, class_name:"User", foreign_key:"funder_id"
has_many :matches
has_many :researchers, class_name: "User", source: :user, through: :matches
class User < ActiveRecord::Base
has_many :matches
has_many :grants, through: :matches
class Match < ActiveRecord::Base
belongs_to :user
belongs_to :grant
Or ——————————————————————
class Grant < ActiveRecord::Base
has_many :funder_matches, :foreign_key => :researcher_id, :class_name => "Match"
has_many :researcher_matches, :foreign_key => :funder_id, :class_name => "Match"
has_many :researchers, through: :researcher_matches
has_many :funders, through: :funder_matches
class Match < ActiveRecord::Base
belongs_to :grant
belongs_to :user
belongs_to :funder, :class_name => "User"
belongs_to :researcher, :class_name => "User"
class User < ActiveRecord::Base
has_many :matches
has_many :grants, through: :matches
and then in the meantime grants are created by admin by visiting the users profile and passing in the user_id.
In the grant model I have:
def create_grant_with_associations(current_user)
current_user.grants << self
self.funder = current_user
self.save
end
I also have funder_id on the Grants table and in the grant controller I have
def create
#grant = ##user.grants.build(grant_params)
if #grant.save
#grant.create_grant_with_associations(##user)
flash[:info] = "The grant was successfully created"
redirect_to #grant
else
render 'new'
end
end
and then finally I have a collection select to allow admin to select grants and match them with the user.
<h4>Match a grant:</h4>
<%= form_for #user, :html => { :class => 'form-horizontal', :multipart => true } do |f| %>
<div class="field ">
<%= f.label :grants, "Select Grant" %>
<%= f.collection_select(:grant_ids, Grant.all, :id, :name,{:include_blank => 'Show No Grants Matched'}, :multiple => true) %>
</div>
<%= f.submit "Create Match", class: "btn btn-primary"%>
<% end %>
The problem I'm having now is that when i use the collection select it overrides the funder association. Am I on the right track?