issue and error message : Couldn't find School with 'id'= - ruby-on-rails

What I want to achieve is that list each member with schools and thereafter list Schools with all belonging members. Schools can have many members and members can have many schools also. I have the following set up in the system, but have problems finding the solution for it. Here it is how my code looks like:
controller:
class MembersController < ActionController::Base
before_action :set_school
def index
#members = Member.all
end
def new
#member = Member.new
end
def create
#member = Member.new(member_params)
#member.school = #school
#member.save
redirect_to members_path
end
private
def set_school
#school = School.find(params[:school])
end
def member_params
params.require(:member).permit(:name, :email,:school)
end
end
This is my route:
Rails.application.routes.draw do
get 'schools/index'
resources :members
resources :school
end
My view looks like:
<% #members.each do |member| %>
<%= member.name %>
<%= member.email %>
<%= member.school %>
<% end %>
model for members:
class CreateMembers < ActiveRecord::Migration[5.0]
def change
create_table :members do |t|
t.string :name
t.string :email
t.timestamps
end
end
my School model :
class CreateSchools < ActiveRecord::Migration[5.0]
def change
create_table :schools do |t|
t.string :name
t.timestamps
end
and the reference:
class AddSchoolRefToMembers < ActiveRecord::Migration[5.0]
def change
add_reference :members, :school, foreign_key: true
end
Any help would be great! Thank you!

You have set before_action for all actions in controller. For, index and new there is no school_id, so you have to run before_action only for create.
Change below code
before_action :set_school
to
before_action :set_school, only: ['create']

<%= simple_form_for [#member] do |f| %>
<%= f.input :name %>
<%= f.input :email %>
<%= f.collection_select :school_id, School.all, :id, :name %>
<%= f.submit %>
<% end %>
Change the strong params
def member_params
params.require(:member).permit(:name, :email, :school_id)
end
And you can remove the before_action :set_school
Also you need to change the action as school_id is already in params
def create
#member = Member.create(member_params)
redirect_to members_path
end

#imocsari to get the name of school change your view like
<% #members.each do |member| %>
<%= member.name %>
<%= member.email %>
<%= member.school.try(:name) %>
<% end %>
member.school will give you associated school of member with all column, if you want to show name of school this is way member.school.try(:name) or member.school.name
member.school.try(:name) this will return nil if there is not any school for member, It will by pass exception
member.school.name this will raise error if there is not any school for member.

Related

Getting error uninitialized constant when attempting to save form to database (Ruby on Rails)

I am getting an error "uninitialized constant Admins::ProductsController::Product", I have been trying to figure out what I'm doing wrong all day and not getting anywhere.
I am trying to submit data to a database through a form. I also have the controller and models in a subdirectory "admins".
controllers/admins/products_controller.rb
class Admins::ProductsController < ApplicationController
def new
end
def show
#product = Product.find(params[:id])
end
def create
#product = Product.new(product_params)
#product.save
redirect_to #product
end
private def product_parms
params.require(:product).permit(:title, :content)
end
end
views/admins/products/new.html.erb
<%= render 'layouts/adminsidebar' %>
<%= form_for :product, url: admins_products_path do |f| %>
<%= f.label :title %>
<%= f.text_field :title %>
<%= f.label :content%>
<%= f.text_area :content%>
<%= f.submit %>
<% end %>
routes.rb
namespace :admins do
get 'new' => 'products#new'
resources :products
end
devise_for :users
root 'pages#index'
get 'about' => 'pages#about'
get 'productsdis' => 'products#productsdis'
get 'adminpanel' => 'admins#adminpanel'
get 'admin' => 'admins#admin'
end
Migration file
def change
create_table :admin_products do |t|
t.string :title
t.text :content
t.timestamps
end
end
end
models/admin/product.rb
class Admin::Product < ApplicationRecord
end
Your calling Product.new in your Admin::ProductsController where it should be Admin::Product.new

ActiveRecord::NotNullViolation (PG::NotNullViolation: ERROR: null value in column "content_id" violates not-null constraint

I'm currently building a rails 5 application in which a shout can be a TextShout or a PhotoShout. When creating a shout, content_id is not being pass in the params therefore raising a Not Null Value error. In the migration for the shout I can not find where the error is coming from. I have the following files.
show.html.erb
<%= form_for #shout do |form| %>
<%= form.hidden_field :content_type, value: "TextShout" %>
<%= form.fields_for :content do |content_form| %>
<%= content_form.text_field :body, placeholder: "shout here!", required: true %>
<%= content_form.submit "Shout!" %>
<% end %>
<% end %>
<%= form_for #shout do |form| %>
<%= form.hidden_field :content_type, value: "PhotoShout" %>
<%= form.fields_for :content do |content_form| %>
<%= content_form.file_field :image, required: true %>
<%= content_form.submit "Shout!" %>
<% end %>
<% end %>
<%= render #shouts %>
migration/_make_shouts_polymorphic.rb
class MakeShoutsPolymorphic < ActiveRecord::Migration[5.1]
class Shout < ApplicationRecord
belongs_to :content, polymorphic: true
end
class TextShout < ApplicationRecord; end
def change
change_table(:shouts) do |t|
t.string :content_type
t.integer :content_id
t.index [:content_type, :content_id]
end
reversible do |dir|
Shout.reset_column_information
Shout.find_each do |shout|
dir.up do
text_shout = TextShout.create(body: shout.body)
shout.update(content_id: text_shout.id, content_type: "TextShout")
end
dir.down do
shout.update(body: shout.content.body)
shout.content.destroy
end
end
end
remove_column :shouts, :body, :string
end
end
shouts_controller.rb
class ShoutsController < ApplicationController
def show
#shout = Shout.find(params[:id])
end
def create
shout = current_user.shouts.create(shout_params)
redirect_to root_path, redirect_options_for(shout)
end
private
def shout_params
{ content: content_from_params }
end
def content_from_params
case params[:shout][:content_type]
when "TextShout" then TextShout.new(text_shout_content_params)
when "PhotoShout" then PhotoShout.new(photo_shout_content_params)
end
end
def text_shout_content_params
params.require(:shout).require(:content).permit(:body)
end
def photo_shout_content_params
params.require(:shout).require(:content).permit(:image)
end
def redirect_options_for(shout)
if shout.persisted?
{notice: "Shouted Successfully"}
else
{alert: "Could not shout"}
end
end
end
neither text_shout_content_params and photo_shout_content_params are permitting a content_id, but it looks like you're trying to (or at least you should be intending to) create one in your content_from_params
def content_from_params
case params[:shout][:content_type]
when "TextShout"
shout = TextShout.new(text_shout_content_params)
when "PhotoShout"
shout = PhotoShout.new(photo_shout_content_params)
end
shout.save!
params[:shout][:content_id] = shout.id
params[:shout]
end
If you want the content to have an id you will have to create the shout using create instead of new. create will attempt to add a record to the database and will assign an id.
It may also be beneficial to use create! which will raise an error if the shout has invalid data and cannot be saved.
def content_from_params
case params[:shout][:content_type]
when "TextShout" then TextShout.create(text_shout_content_params)
when "PhotoShout" then PhotoShout.create(photo_shout_content_params)
end
end

Dealing With Multiple Objects

I am new to Rails and currently trying to add a patient to an existing dentist appointment. I am having difficulty setting up my views and controllers properly. How can I properly accomplish this?
Note: With the way I have set things up, I can create an appointment and tie it to a dentist. Of course, the patient_id is missing.
Models:
class Dentist < ActiveRecord::Base
has_many :appointments
has_many :patients, :through => :appointments
end
class Appointment < ActiveRecord::Base
belongs_to :dentists
belongs_to :patients
end
class Patient < ActiveRecord::Base
has_many :appointments
has_many :dentists, :through => :appointments
end
Schema:
ActiveRecord::Schema.define(version: 20151107052115) do
create_table "appointments", force: :cascade do |t|
t.integer "dentist_id"
t.integer "patient_id"
t.datetime "appt_date"
end
create_table "dentists", force: :cascade do |t|
t.string "name"
end
create_table "patients", force: :cascade do |t|
t.string "name"
end
end
Routes:
Rails.application.routes.draw do
concern :commentable do
resources :appointments
end
resources :dentists, concerns: :commentable
resources :patients, concerns: :commentable
end
Dentists Controller:
class DentistsController < ApplicationController
def new
#dentist = Dentist.new
end
def create
#dentist = Dentist.new(dentist_params)
if #dentist.save
redirect_to dentists_path
else
render :new
end
end
...
end
Appointments Controller:
class AppointmentsController < ApplicationController
def new
#dentist = Dentist.find(params[:dentist_id])
#appointment = #dentist.appointments.new
end
def create
#dentist = Dentist.find(params[:dentist_id])
#appointment = #dentist.appointments.new(appt_params)
if Appointment.exists?(:appt_date => #appointment.appt_date)
render :new
else
#appointment.save
redirect_to dentist_path(#dentist)
end
end
...
end
Patients Controller:
TBD
Dentists View (Show):
<p><%= #dentist.name %> DDS</p>
<% if #dentist.appointments.any? %>
<% #dentist.appointments.each do |appt| %>
<ul>
<li><%= appt.appt_date %></li>
<p><%= link_to "Edit", edit_dentist_appointment_path(#dentist, appt) %> |
<%= link_to 'Delete', dentist_appointment_path(#dentist, appt), :method => :delete,
data: {:confirm => 'Are you sure you want to delete this record?'} %> |
<%= link_to 'Add Patient', new_patient_path %></p>
</ul>
<% end %>
<% else %>
<p>There are currently no appointments scheduled</p>
<% end %>
<p><%= link_to 'Delete Dentist', dentist_path(#dentist), :method => :delete,
data: {:confirm => 'Are you sure you want to delete this record?'} %></p>
<p><%= link_to 'Create an appointment', new_dentist_appointment_path(#dentist) %></p>
<p><%= link_to 'Return to list', root_path %></p>
I am new to Rails
Welcome!
You need to change your belongs_to references to be singular:
class Appointment < ActiveRecord::Base
belongs_to :dentist
belongs_to :patient
end
--
Because I can't see where you're trying to achieve this functionality, I'll show you what I'd do (using the appointment#edit action):
#app/controllers/appointments_controller.rb
class AppointmentsController < ApplicationController
def edit
#appointment = Appointment.find params[:id]
end
def update
#appointment = Appointment.find params[:id]
#appointment.save appointment_params
end
private
def appointment_params
params.require(:appointment).permit(:dentist_id, :patient_id, :appt_date)
end
end
#app/views/appointments/edit.html.erb
<%= form_for #appointment do |f| %>
<%= f.collection_select :patient_id, Patient.all, :id, :name %>
<%= f.submit %>
<% end %>
--
If you're trying to set the patient from your appointments#create method, you'll be best doing this:
#app/controllers/appointments_controller.rb
class AppointmentsController < ApplicationController
def new
#dentist = Dentist.find params[:id]
#appointment = #dentist.appointments.new
end
def create
#dentist = Dentist.find params[:id]
#appointment = #dentist.appointments.new appointment_params
end
private
def appointment_params
params.require(:appointment).permit(:dentist_id, :patient_id, :appt_date)
end
end
#app/views/appointments/new.html.erb
<%= form_for #appointment do |f| %>
<%= f.collection_select :patient_id, Patient.all, :id, :name %>
<%= f.submit %>
<% end %>
I think what you are asking, is can you create an appointment through both the Dentist model and the Patient model at the same time eg. #dentist.#patient.apointment.new
you cannot do that. Based on the relationships you have set up, you will either want to create the appt from the Dentist, like you have now, and pass in the patient ID as an attribute, or vice-versa. OR, create through your Appointment model eg. Appointment.new(dentist: #dentist, patient: #patient, ...)

Rails polymorphic posts associations and form_for in views

I've been having trouble setting up the form for a polymorphic "department" post in the department view. I followed the rails-cast tutorial for polymorphic associations here
Models:
class Course < ActiveRecord::Base
belongs_to :department, inverse_of: :courses
has_and_belongs_to_many :users, -> { uniq }
has_many :posts, as: :postable #allows polymorphic posts
end
class Department < ActiveRecord::Base
has_many :courses, inverse_of: :department
has_many :posts, as: :postable #allows polymorphic posts
has_and_belongs_to_many :users, -> {uniq}
end
class Post < ActiveRecord::Base
belongs_to :user, touch: true #updates the updated_at timestamp whenever post is saved
belongs_to :postable, polymorphic: true #http://guides.rubyonrails.org/association_basics.html#polymorphic-associations
belongs_to :department, counter_cache: true #for counting number of posts in department
belongs_to :course, counter_cache: true
validates :department_id, :course_id, presence: true
end
config/routes
devise_for :users
devise_scope :users do
match '/users/:id', to: "users#show", via: 'get'
end
resources :departments do
resources :courses
resources :posts
end
resources :courses do
resources :posts
end
views/departments/show.html.erb
<div class="tab-pane" id="posts"><br>
<center><h3>Posts:</h3></center>
<%= render "posts/form", postable: #department %>
</div>
views/posts/_form.html.erb
<%= render "posts/wysihtml5" %>
<center><h3>Create New Post:</h3></center>
<%= form_for [#postable, Post.new] do |f| %>
<%= f.label :title %>
<%= f.text_field :title, class: "form-control" %>
<%= f.label :description %>
<%= f.text_area :description, :rows => 3, class: "form-control" %>
<%= f.text_area :content, :rows => 5, placeholder: 'Enter Content Here', class: "wysihtml5" %>
<span class="pull-left"><%= f.submit "Create Post", class: "btn btn-medium btn-primary" %></span>
<% end %>
controllers/post_controller.rb
class PostsController < ApplicationController
before_filter :find_postable
load_and_authorize_resource
def new
#postable = find_postable
#post = #postable.posts.new
end
def create
#postable = find_postable
#post = #postable.posts.build(post_params)
if #post.save
flash[:success] = "#{#post.title} was sucessfully created!"
redirect_to department_post_path#id: nil #redirects back to the current index action
else
render action: 'new'
end
end
def show
#post = Post.find(params[:id])
end
def index
#postable = find_postable
#posts = #postable.posts
end
...
private
def post_params
params.require(:post).permit(:title, :description, :content)
end
def find_postable #gets the type of post to create
params.each do |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.find(value)
end
end
nil
end
controllers/departments_controller.rb
def show
id = params[:id]
#department = Department.find(id)
#course = Course.new
#course.department_id = #department
end
The error is "undefined method `posts_path' for #<#:0x0000010d1dab10>"
I think the error has something to do with the path in the form, but I don't know what. I've tried [#postable, #postable.posts.build] as well but that just gives me undefined method: PostsController.
Anybody know what's going on and how I can fix it?
#department is passed into the form partial as a local variable, but the form calls an instance variable:
# views/departments/show.html.erb
<%= render "posts/form", postable: #department %> # <------ postable
# views/posts/_form.html.erb
<%= form_for [#postable, Post.new] do |f| %> # <------ #postable
Thus, the namespaced route is not properly determined
[#postable, Post.new] # => departments_posts_path
[ nil , Post.new] # => posts_path
Checking your routes, posts are only accessible via nested routes. posts_path is not a valid route, it's method does not exist, and the error is correct: undefined method `posts_path'
Fix:
Set a #postable instance variable in the departments controller so that the form helper can use it:
def show
id = params[:id]
#postable, #department = Department.find(id) # <-- add #postable
#course = Course.new
#course.department_id = #department
end
Then you can simply call render in the view:
<%= render "posts/form" %>

company and user create in one form

Im trying to make a sign up form where you can create a user and a company at the same time. I have a user table and a company table.
user model
belongs_to :companies
accepts_nested_attributes_for :companies
company model
has_many :users
users controller
def new
#users = User.new
#companies = Company.new
end
def create
#companies = Company.create(company_params)
#users = #companies.user.create(user_params)
#users.save
redirect_to :back
end
private
def user_params
params.require(:user).permit(:name)
end
def company_params
params.require(:user).permit(:name)
end
Routes
resources :users
resources :companies
new.html.erb
<%= form_for(#users) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.fields_for #companies do |build| %>
<%= build.text_field :name %>
<% end %>
<%= f.submit %>
<% end %>
So this create a company and a user at the same time. But i want the user to be assigned a company_id there belongs to the company they just created. I have the company_id field in my users table. Any ideas?
UPDATE
def create
#companies = Company.create(company_params)
c = Company.last
#users = c.users.create(user_params)
#users.save
redirect_to :back
end
I did add this to the user controller at it works, but it doesn't seems like the best solution. Please correct me if i'm wrong.
Thanks in advance
I would do in the following way:
Your User Model
belongs_to :companies,:inverse_of => :users
accepts_nested_attributes_for :companies
Your controller
def new
#users = User.new
#users.build_company
end
def create
#users = User.new(user_company_params)
#users.save
end
def user_company_params
params.require(:user).permit(:name, companies_attributes: name)
end
Your View
<%= f.fields_for :companies do |build| %>
<%= build.text_field :name %>
<% end %>
It works for me :)
Source:
http://guides.rubyonrails.org/association_basics.html

Resources