Instance Variable Definition in Controller Issue: Rails 5 - ruby-on-rails

I have a single user table with two roles defined using enums and Single Table Inheritance with two matching user sub classes for Staff and Clinician. Because I need a lot of information about clinicians that I don't need about Staff, I've created a clinician_profiles table and am using after_create :create_clinician_profile in the user model to create a stub for the clinician profile.
I am trying to build a page for clinicians to complete their profiles and am having trouble getting the instance variable defined in the controller so it pulls the appropriate clinician's profile into the view to render the form. I am getting the following error. Note that the user's id I'm logged in as is 104.
ActiveRecord::RecordNotFound in ClinicianProfilesController#edit
Couldn't find ClinicianProfile with 'id'=104
I feel like I'm close but don't know what I'm doing wrong. Any help would be greatly appreciated for a rookie!
I'm landing on the page using this link in the header:
<li><%= link_to "Manage My Profile", edit_clinician_profile_path(current_user) %></li>
Here are relevant parts of my user model:
class User < ApplicationRecord
self.inheritance_column = :role
enum role: { Staff: 0, Clinician: 1}
belongs_to :university
has_many :referral_requests
class Staff < User
validates :university_id, presence: true
end
class Clinician < User
has_many :lists
has_many :universities, through: :lists
has_one :clinician_profile
after_create :create_clinician_profile
end
Here's my ClinicianProfile model:
class ClinicianProfile < ApplicationRecord
has_many :clinician_profile_languages
has_many :languages, through: :clinician_profile_languages
has_many :clinician_profile_races
has_many :races, through: :clinician_profile_races
belongs_to :clinician
end
clinician_profiles schema
create_table "clinician_profiles", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "firstname"
t.string "lastname"
t.string "address1"
t.string "address2"
t.string "city"
t.string "state"
t.string "zip"
t.boolean "accepting_patients"
t.integer "rate"
t.string "license_number"
t.string "license_state"
t.string "school"
t.integer "year_graduated"
t.string "accepts_insurance"
t.boolean "sliding_scale"
t.text "bio"
t.boolean "verified"
t.integer "years_licensed"
t.integer "years_of_experience"
t.integer "clinician_id"
end
ClinicianProfilesController
class ClinicianProfilesController < ApplicationController
def edit
#clinician_profile = ClinicianProfile.find(params[:id])
end
def index
end
def show
end
def create
end
end
Here's the beginning of my view (edit.html.erb in /views/clinician_profiles)
<%= form_for(#clinician_profile) do |f| %>
<%= render 'shared/error_messages', object: f.object %>

def edit
#clinician_profile = ClinicianProfile.find(params[:id])
redirect_to :index and return unless #clinician_profile
end

Related

ActiveModel::MissingAttributeError (can't write unknown attribute `flights_count`):

I am doing some refactoring and I have seen this project for a while and it worked from what I last recall. But the issue is, I am trying to create a flight and I keep getting "ActiveModel::MissingAttributeError (can't write unknown attribute flights_count):" when trying create a new flight.
As far my models in place:
My Flight, Pilot models
class Flight < ActiveRecord::Base
has_many :passengers
belongs_to :destination
belongs_to :pilot, counter_cache: true
accepts_nested_attributes_for :passengers
belongs_to :user, class_name: "Flight" ,optional: true
validates_presence_of :flight_number
validates :flight_number, uniqueness: true
scope :order_by_flight_international, -> { order(flight_number: :asc).where("LENGTH(flight_number) > 3") }
scope :order_by_flight_domestic, -> { order(flight_number: :asc).where("LENGTH(flight_number) <= 2 ") }
def dest_name=(name)
self.destination = Destination.find_or_create_by(name: name)
end
def dest_name
self.destination ? self.destination.name : nil
end
def pilot_name=(name)
self.pilot = Pilot.find_or_create_by(name: name)
end
def pilot_name
self.pilot ? self.pilot.name : nil
end
end
class Pilot < ActiveRecord::Base
belongs_to :user, optional: true
has_many :flights
has_many :destinations, through: :flights
validates_presence_of :name, :rank
validates :name, uniqueness: true
scope :top_pilot, -> { order(flight_count: :desc).limit(1)}
end
Edit
Flight Controller
class FlightsController < ApplicationController
before_action :verified_user
layout 'flightlayout'
def index
#flights = Flight.order_by_flight_international
#dom_flights = Flight.order_by_flight_domestic
end
def new
#flight = Flight.new
10.times {#flight.passengers.build}
end
def create
#flight = Flight.new(flight_params)
# byebug
if #flight.save!
redirect_to flight_path(current_user,#flight)
else
flash.now[:danger] = 'Flight Number, Destination, and Pilot have to be selected at least'
render :new
end
end
private
def flight_params
params.require(:flight).permit(:flight_number,:date_of_flight, :flight_time, :flight_id, :destination_id, :pilot_id, :pilot_id =>[], :destination_id =>[], passengers_attributes:[:id, :name])
end
end
Edit
Flights, Pilot Schemas
create_table "flights", force: :cascade do |t|
t.integer "pilot_id"
t.integer "destination_id"
t.string "flight_number"
t.string "date_of_flight"
t.string "flight_time"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "pilots", force: :cascade do |t|
t.string "name"
t.string "rank"
t.integer "user_id"
t.integer "flight_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "flight_count", default: 0
end
As I said before when I last worked on this project everything was working fine, but I am faced with this issue. What am I doing wrong this time.
You have defined a counter_cache in your Flight model for pilots. When you just use counter_cache: true to define it, ActiveRecord will look for a column named flights_count in your pilots table but I see that you have named it as flight_count instead. You can either rename the column to flights_count or pass the custom column name to it by using counter_cache: :flight_count
Source https://guides.rubyonrails.org/association_basics.html#options-for-belongs-to-counter-cache

How do I set/limit the input in a rails form to match another models table?

I'm quite new to programming and haven't been able to find any resources to help me with this. I have created two scaffolds Accounts and Cashbooks. I want users to be able to add an account (with a parameter of account_name) which will then be set as the parameters for the Cashbook account input. Ideally when adding a Cashbook transaction, I would want users to see a dropdown which will contain all the account_names of the Accounts which have been created.
Cashbook Model
class Cashbook < ActiveRecord::Base
belongs_to :account, foreign_key: :account_name
end
Cashbook Controller
def new
#cashbook = Cashbook.new
#cashbook.account(account_params[:account_name])
end
def create
#cashbook = Cashbook.new(cashbook_params)
#cashbook.account(account_params[:account_name])
def cashbook_params
params.require(:cashbook).permit(:date, :description, :account, :kind, :amount, :balance, :name)
params.require(:account).permit(:account_name)
end
Cashbook DB
class CreateAccounts < ActiveRecord::Migration
def change
create_table :accounts do |t|
t.string :account_name
t.boolean :operating_expense
t.boolean :cost_of_sales
t.boolean :sales
t.boolean :other_income
t.boolean :non_current_liability
t.boolean :non_current_asset
t.boolean :current_asset
t.boolean :current_liability
t.boolean :equity
t.integer :account_number
t.timestamps null: false
end
end
end
Account Model
class Account < ActiveRecord::Base
has_many :cashbook, foreign_key: :account_name
end
Account Controller
def new
#account = Account.new
end
def edit
end
def create
#account = Account.new(account_params)
end
def account_params
params.require(:account).permit(:account_name, :operating_expense, :cost_of_sales, :sales, :other_income, :non_current_liability, :non_current_asset, :current_asset, :current_liability, :equity, :account_number)
end
Cashbook db
class CreateCashbooks < ActiveRecord::Migration
def change
create_table :cashbooks do |t|
t.date :date
t.string :description
t.boolean :account
t.string :kind
t.integer :amount
t.timestamps null: false
end
end
end
You can use the collection_select form helper.
In your case, it could look something like
<%= collection_select(:cashbook, :account_name, Account.all, :account_name, :account_name) %>
Though you should also consider using the id column to associate models as per the Rails Associations Guide. If you change your models to use ids as the foreign key, you won't need to explicitly specify the foreign key in your has_many and belongs_to statements, and you can still create a select box that displays account names:
<%= collection_select(:cashbook, :account_id, Account.all, :id, :account_name) %>

Rails : Associating a record with a user who did not create that record

I have a user model and a patient model. Patients are not users of the application. Users are essentially staff members who are creating patient records. In some situations, the user who creates the patient's record is also that patient's physician. In other cases, the patient's physician could be a separate user.
I want to save the user id of the patient's physician to the patient model rather than the user who happened to create the patient. The implementation I am imagining is that I will have a dropdown field in the form for the user to select the patient's physician, including the option to select themselves. How can I do this? Am I even thinking about this the right way? Here is my current implementation:
class Patient < ApplicationRecord
belongs_to :user
class User < ApplicationRecord
has_many :patients
Patients Controller
class PatientsController < ApplicationController
def new
#patient = current_user.patients.build
end
def create
#patient = current_user.patients.build(patient_params)
if #patient.save
flash[:success] = "Patient Created!"
redirect_to new_referral_request_path(patient_id: #patient.id)
else
Rails.logger.info(#patient.errors.inspect)
render 'patients/new'
end
end
private
def patient_params
params.require(:patient).permit(:age, :user_id, insurance_ids: [], gender_ids: [], concern_ids: [], race_ids: [])
end
end
patient's schema:
create_table "patients", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "age"
t.string "user_id"
t.index ["user_id"], name: "index_patients_on_user_id"
end
I have two roles: one for staff and one for clinician. Staff users would be the ones creating patients. A staff user who creates a patient record may or may not be that particular patient's physician.
class User < ApplicationRecord
self.inheritance_column = :role
enum role: { Staff: 0, Clinician: 1}
Just add physician relation to Patient model:
class Patient < ApplicationRecord
belongs_to :user
belongs_to :physician, class_name: 'User'
end
Then modify schema:
create_table "patients", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "age"
t.string "user_id"
t.integer "physician_id"
t.index ["user_id"], name: "index_patients_on_user_id"
t.index ["physician_id"], name: "index_patients_on_physician_id"
end
Hint: use integer for your ids fields, if your ids are numeric.
(Of course, its better to do this through migration, see this post if you don't know how).
Then permit physician_id in params:
def patient_params
params.require(:patient).permit(:age, :user_id, :physician_id, insurance_ids: [], gender_ids: [], concern_ids: [], race_ids: [])
end
And finally add dropdown list in the form:
<%= form_for(#patient) do |f| %>
<%= f.select :physician_id, User.all.map { |u| [u.name, u.id] } %>
...other fields...
<% end %>
Now you can call both patient.user and patient.physician (which can be equal).

Belongs To Association Table Schema Ruby on Rails

I want each student to be able to post multiple messages on my site.
therefore each student has_many :posts
and a post belongs_to :student (one student only)
The thing is I can create a record for a student in rails console but can't assign a post to the student ? I am a bit confused. The student model with the has many does not have the attributes from the belongs to model ?
I have a student.rb model
class Student < ActiveRecord::Base
attr_accessible :first_name, :last_name, :email, :gender, :number, :college, :password, :budget, :picture
mount_uploader :picture, PictureUploader
has_many :posts
end
I have a post.rb model
class Post < ActiveRecord::Base
attr_accessible :message
belongs_to :student
end
this is my schema
ActiveRecord::Schema.define(version: 20130827191617) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "posts", force: true do |t|
t.text "message"
end
create_table "students", force: true do |t|
t.string "first_name"
t.string "last_name"
t.string "email"
t.string "number"
t.string "college"
t.string "password"
t.float "budget"
t.string "picture"
t.datetime "created_at"
t.datetime "updated_at"
end
You should add student_id integer column (it would be better if there was also index on this column) to posts table.
To do this, you can type in console:
bundle exec rails g migration add_student_id_to_posts student:references

Rails - Single User Multiple "Roles?"

Having an invoice model which belongs to user, and a user table that associates a user as a particular role or multiple roles:
class CreateInvoices < ActiveRecord::Migration
def self.up
create_table :invoices do |t|
t.string :po_number
t.datetime :invoice_date
t.datetime :date_received
t.datetime :date_approved
t.text :clerk_note
t.integer :clerk_id
t.integer :approver_id
t.text :approver_note
end
end
class Invoice < ActiveRecord::Base
belongs_to :user
end
class CreateUsers < ActiveRecord::Migration
def self.up
create_table :users do |t|
t.string :first_name
t.string :last_name
t.string :username
t.string :email
t.boolean :account_clerk
t.boolean :approver
t.boolean :admin
end
end
class User < ActiveRecord::Base
has_many :invoices
end
In the invoice record, how do I assign an clerk_id and approver_id depending on the role set in the user model? Each invoice will have a clerk and approver, but both are users.
Likewise, how do I assign the clerk_note to the clerk_id and the approver_note to the approver_id? I'm assuming in this case, I can just refer to current_user, since the user logged in will be the one making the note, right?
I'm not sure what this is called, so in my Googling, I didn't know what to look for... thanks in advance for your help.
To answer your original question using your current models you can just create your view to display different fields based on the role of the user (this assumes the logged in user is in an instance variable named #user).
<% if (#user.approver) then %>
<%= f.text_area :approver_note %>
<% else %>
<%= f.text_area :clerk_note %>
<% end %>
Then in your controller you can set the value of clerk id or approver id again depending on the logged in user.
if (#user.approver) then
#invoice.approver_id = #user.id
else
#invoice.clerk_id = #user.id
end

Resources