Unknown attribute error after renaming a foreign key - ruby-on-rails

I have three user roles:
enum role: { staff: 0, clinician: 1, admin: 2 }
I had a user_id column in my patients table to store the id of the staff user who created the patient record. To improve the clarity of the name, I renamed the column from user_id to author_id and adjusted the relationship best I knew how to reference the change to the foreign key.
When I try to access /patients/new, I get the error:
unknown attribute 'user_id' for Patient.
The error specifically highlights this line in my new patients method:
#patient = current_user.patients.build
What am I doing incorrectly? Thanks for any help!
patients table:
create_table "patients", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "age"
t.integer "staff_clinician_id"
t.integer "author_id"
t.index ["author_id"], name: "index_patients_on_author_id"
t.index ["staff_clinician_id"], name: "index_patients_on_staff_clinician_id"
end
Patient Model
class Patient < ApplicationRecord
belongs_to :user, -> { where role: :staff }, foreign_key: 'author_id'
Staff User concern
require 'active_support/concern'
module StaffUser
extend ActiveSupport::Concern
included do
belongs_to :university
has_many :patients
has_many :referral_requests
validates :university_id, presence: true, if: :staff?
end
class_methods do
end
end
Here is my patients controller:
class PatientsController < ApplicationController
before_action :require_login
def new
#patient = current_user.patients.build
end
def index
authorize Patient
#patients = policy_scope(Patient)
end
def show
#patient = Patient.find(params[:id])
end
def edit
#patient = Patient.find(params[:id])
end
def update
#patients = Patient.all
#patient = Patient.find(params[:id])
if #patient.update_attributes(patient_params)
flash[:success] = "Patient Updated!"
render 'patients/index'
else
render "edit"
end
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, :staff_clinician_id, :author_id, insurance_ids: [], gender_ids: [], concern_ids: [], race_ids: [])
end
end

Seems you have a User model with has_many :patients (I assume that's where you used your StaffUser concern). Rails infers that the foreign key on the association table is user_id. You need to change this to:
##user.rb
has_many :patients, foreign_key: "author_id"

Related

Transactions rolling back: user does not exist

I am trying to add the username of an author to a post in my blog, in order to later be able to verify that the user attempting to alter the post is the original author of the post. However, it is not working, and is returning the error "Validation failed: User must exist", even though the current user does exist, based on the fact that it is displaying the username of the currently logged in user on the page.
Error log:
Validation failed: User must exist
#post = Post.new(post_params)
#post[:author] = current_user.username
->> if #post.save!
flash[:success] = "Post created."
redirect_to post_path(#post.id)
else
Application controller (where current_user is declared):
class ApplicationController < ActionController::Base
helper_method :current_user
helper_method :require_user
def current_user
return unless session[:user_id]
current_user ||= User.find(session[:user_id])
end
def require_user
redirect_to '/login' unless current_user
end
end
Post model:
class Post < ApplicationRecord
has_many :comments
belongs_to :category
belongs_to :user
end
Schema:
create_table "posts", force: :cascade do |t|
t.string "title"
t.integer "category_id"
t.string "author"
t.text "body"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Error when I do what Vasilisa said:
ActiveRecord::AssociationTypeMismatch (User(#47015106648260) expected, got "test" which is an instance of String(#47015080074780)):
def create
#post = current_user.posts.build(post_params)
==> #post.author = current_user.username
if #post.save
flash[:success] = "Post created."
redirect_to post_path(#post.id)
The Post model belongs_to :user, in ROR 5 this association validates for presence automatically. That's why you're getting "Validation failed: User must exist". Looks like you want to store post's user as author in db.
Change your posts table in migration
def change
remove_column :posts, :author, :string
add_reference :posts, :author
end
In the Post model change belongs_to :user to belongs_to :author, class_name: 'User'
Add to the User model
has_many :posts, foreign_key: :author_id
After it you can just write current_user.posts in the controller
def create
#post = current_user.posts.build(post_params)
if #post.save
flash[:success] = "Post created."
redirect_to post_path(#post.id)
else
render :new
end
end
And please, read again about associations in Rails

Record not saving to join table in has_many through relationship

In this Rails app, Users write Stories. Users can create Collections to group their Stories. However, they are allowed to publish Stories that don't belong to any Collection.
When creating a Story, I want the join table Story_Collections to save the Collection/Story ID pairs but it isn't working. Any help is appreciated! :)
Here's what I have
collection.rb
class Collection < ActiveRecord::Base
belongs_to :user
has_many :story_collections
has_many :stories, through: :story_collections
end
story.rb
class Story < ActiveRecord::Base
belongs_to :user
has_many :story_collections
has_many :collections, through: :story_collections
has_many :photos
end
story_collection.rb
class StoryCollection < ActiveRecord::Base
belongs_to :story
belongs_to :collection
end
In views/stories/new.html.erb
<%= f.select :collection_ids, Collection.all.pluck(:name, :id), {}, { multiple: true, class: "selectize" } %>
Creating the collections in collections_controller.rb
class CollectionsController < ApplicationController
def create
#collection = current_user.collections.build(collection_params)
if #collection.save
render json: #collection
else
render json: {errors: #collection.errors.full_messages}
end
end
private
def collection_params
params.require(:collection).permit(:name, :description)
end
end
Creating the stories
class StoriesController < ApplicationController
def new
#story = Story.new
authorize #story
end
def create
#story = current_user.stories.build(story_params)
authorize #story
end
private
def story_params
params.require(:story).permit(:title, :description, category_ids: [],
photos_attributes: [:id, :file_name, :file_name_cache, :_destroy])
end
end
The Story and Collection tables are saving correctly, only the join table is not. Here's the schema for the join table.
create_table "story_collections", force: :cascade do |t|
t.integer "story_id"
t.integer "collection_id"
t.datetime "created_at"
t.datetime "updated_at"
end
You are missing strong-params permitting the parameter story[collection_ids]
def story_params
params.require(:story).permit(
:title,
:description,
collection_ids: [], # you need to whitelist this, so the value gets set
category_ids: [],
photos_attributes: [
:id,
:file_name,
:file_name_cache,
:_destroy
]
)
end

How do I param the Controller Favorite Create method to have an index#view

I want to create a polymorphic model to favorite each objects I want to create to stock in my user page.
I am developing a web app to learn japanese and we can favorite different types of cards as kanas or kanjis and sentences.
So there are 3 objects and soon more to favorite.
I migrated a table which names Favorite :
create_table "favorites", force: :cascade do |t|
t.integer "user_id"
t.integer "favoritable_id"
t.string "favoritable_type"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Here is the Favorite model belongs_to
class Favorite < ActiveRecord::Base
belongs_to :favoritable, polymorphic: true
belongs_to :user
end
Here are the Cards model has_many
class Symbole < ActiveRecord::Base
accepts_nested_attributes_for :kanji_attribute, :allow_destroy => true
has_many :sentence_symboles, :class_name => "SentenceSymbole", :foreign_key => "symbole_id"
has_many :favorites, as: :favoritable
end
and I added in sentence model too
class Sentence < ActiveRecord::Base
include Authority::Abilities
has_many :sentence_symboles, :class_name => "SentenceSymbole", :foreign_key => "sentence_id", dependent: :destroy
has_many :favorites, as: :favoritable
end
Now here is the Favorite controller and I don't really know how to write the create method. Here is the Controller I do:
class FavoritesController < ApplicationController
def index
#favorites = Favorite.where(user: current_user)
end
def create
#Favorite.create(user_id: User.last.id, favoritable_id: Symbole.last.id, favoritable_type:"Symbole")
#favorite = current_user.favoritable.favorites.create(symbole: #symbole, sentence: #sentence).first
if #favorite.present?
#favorite.destroy
else
#favorite = current_user.favorites.new(symbole: #symbole, sentence: #sentence)
if not #symbole.favorites.where(user: current_user).take
#sentence.favorites.where(user: current_user).take
#favorite.save
end
end
# redirect_to favs_path
# redirect_to :back
respond_to do |format|
format.js { render :ajax_update_favs }
end
end
def destroy
#favorite = Favorite.find(params[:id])
#favorite.destroy
redirect_to :back
end
end
Please could someone give me the right way to favorite all object I want and add in an favorite index#view.
Thank you for your help.
I think my question is simple but no. How to favorite each object I want with the def Create controller what is the best method?
I do that
def create
#Favorite.create(user_id: User.last.id, favoritable_id: Symbole.last.id, favoritable_type:"Symbole")
#favorite = #favoritable.favorites.build(favorite_params)
#favorite.user = current_user
#favorite.save
respond_to do |format|
format.js { render :ajax_update_favorites }
end
end
Not sure I understood the problem entirely. It looks like you're overcomplicating favoritesController#create. If a record only should be favorited once, you should add a uniqueness validation in the Favorite model.
Assuming that you have your user model set up like
class User < ActiveRecord::Base
has_many :favorites
# Rest..
end
def create
#favorite = current_user.favorites.create(favorite_params)
# This will create a new Favorite with user_id: current_user.id, favoritable_type: "Symbole", favoritable_id: 1337
# Is this the desired behaviour?
respond_to do |format|
format.js { render :ajax_update_favs }
end
end
private
def favorite_params
params.require(:favorite).permit(:favoritable_type, :favoritable_id)
end
If this is called from javascript with jquery pass the type and id that you wan't to favorite.
$.post( "/favorites", {
favorites: {
favoritable_type: "Symbole",
favoritable_id: 1337
}
});

nested form not displaying in Rails

I have a form for a model called isp, which 'has_many' isp accounts. the isp account belongs to to 'isp'.
There is a validation on the isp_account that means it cant be added if there isnt an isp_id, so my reasoning is to created a nested form. I created the nested form like so
= simple_form_for #isp, :html => { :multipart => true } do |f|
= f.input :title
= f.simple_fields_for :isp_accounts do |tag|
= tag.input :title, label: "Tag Name"
however the nested attribute isnt being displayed. There are no errors etc. Why is this? Am I approaching this in the best way? is this the only way?
here's the code
ISP MODEL
class Isp < ActiveRecord::Base
has_many :isp_accounts, dependent: :destroy
has_many :deployments, through: :servers
has_many :servers, through: :isp_accounts
validates :title, presence: true
accepts_nested_attributes_for :isp_accounts
end
ISP ACCOUNTS MODEL
class IspAccount < ActiveRecord::Base
belongs_to :isp
has_many :deployments, through: :servers
has_many :servers, dependent: :destroy
validates :title, presence: true
validate :check_associates
private
def check_associates
associated_object_exists Isp, :isp_id
end
end
ISP ACCOUNT CONTROLLER
....
def new
#isp_account = IspAccount.new
end
def update
#isp_account.update_attributes(isp_accounts_path)
if #isp_account.save
record_saved
return redirect_to(isp_accounts_path)
else
check_for_errors
return render('/isp_accounts/edit')
end
end
private
def get_isp_accounts
#isp_account = IspAccount.all
end
def get_isp_account
#isp_account = IspAccount.find(params_isp_accounts)
end
def params_isp_accounts
params.require(:isp_account).permit!
end
end
....
def new
#isp = Isp.new
end
def update
#isp.update_attributes(params_isp)
if #isp.save
record_saved
return redirect_to(isps_path)
else
check_for_errors
return render('new')
end
end
private
def params_isp
params.require(:isp).permit(:title, isp_accounts_attributes: [:id, :title])
end
def get_isp
#isp = Isp.where(id: params[:id]).first
unless #isp
record_not_found
return redirect_to(isps_path)
end
end
def get_isps
#isp = Isp.all.order(:title)
end
end
SCHEMA
create_table "isp_accounts", force: true do |t|
t.string "title"
t.integer "isp_id"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "isps", force: true do |t|
t.string "title"
t.datetime "created_at"
t.datetime "updated_at"
end
ok i got it. I was missing the new bit for that attribute in my controller. pretty basic really.
def new
#isp = Isp.new
#isp.isp_accounts.new
end

Form Creating nest objects

I have a nested object issue when creating a new item using forms. When I create a new Item within a form and view I created I get a nil on the Product object when trying to access it.
Here is my structure. I have a class called Item and a class called Product. There could be more than 1 item referring to the same Product.
class CreateItem < ActiveRecord::Migration
def change
create_table :items do |t|
t.integer :product_id
t.string :name
t.text :description
t.timestamps
end
end
end
class CreateProducts < ActiveRecord::Migration
def change
create_table :products do |t|
t.string :name
t.text :description
t.decimal :price
t.string :image_file_name
t.integer :inventory
t.timestamps
end
end
end
class Item< ActiveRecord::Base
belongs_to :product
belongs_to :itemstatus
end
class Product < ActiveRecord::Base
has_one :shop
accepts_nested_attributes_for :item
end
Controller Code:
def create
#item= Item.new(params[:item])
if #item.save
redirect_to #item, notice: "Item successfully created!"
else
render :new
end
end
The problem is happening when I go to show the created item. The Product object is nil. I'm not sure what I should be doing to get the Product Object correctly created and added in this process of creating a new Item.
Can someone help me?
Thanks!
params[:item] must be as the following:
#first example
params[:item] = {product_id: 1}
#second example
product = product.create(name: "", description: "", ..)
params[:item] = {product: product}
#third example
#item.product = product
#or
#item.product_id = params[:item][:product_id]
Try to do that:
#item.new(name: params[:item][:name], product_id: params[:item][:product_id], description: params[:item][:description])
help link

Resources