I'm new to rails so I'm still trying to figure things out so any help is greatly appreciated! I am building an app that will define "seasons" and there will be multiple "danceclasses" associated with those seasons. After you create a season, you should have the option to create "danceclasses" so as part of my show on the seasons I have:
<h2>Dance Classes Created</h2>
<%= #seasons.danceclass.each do |danceclass| %>
<p>
However I get the following error:
undefined method `danceclass' for nil:NilClass
My data model is I have a seasons table, a danceclasses table and a season_danceclasses table.
My model for seasons is this:
class Season < ActiveRecord::Base
has_many :season_class
has_many :danceclass, through: :season_class
end
My model for dance classes looks like this:
class Danceclass < ActiveRecord::Base
belongs_to :season
has_many :student_class
has_many :student, through: :student_class
end
And my model for season_danceclass looks like this:
class SeasonDanceclasses < ActiveRecord::Base
belongs_to :season
belongs_to :danceclass
end
My season_controller looks like this:
class SeasonsController < ApplicationController
before_action :set_season, only: [:show, :edit, :update, :destroy]
# GET /seasons
# GET /seasons.json
def index
#seasons = Season.all
end
# GET /seasons/1
# GET /seasons/1.json
def show
end
# GET /seasons/new
def new
#season = Season.new
end
# GET /seasons/1/edit
def edit
end
# POST /seasons
# POST /seasons.json
def create
#season = Season.new(season_params)
respond_to do |format|
if #season.save
format.html { redirect_to #season, notice: 'Season was successfully created.' }
format.json { render :show, status: :created, location: #season }
else
format.html { render :new }
format.json { render json: #season.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /seasons/1
# PATCH/PUT /seasons/1.json
def update
respond_to do |format|
if #season.update(season_params)
format.html { redirect_to #season, notice: 'Season was successfully updated.' }
format.json { render :show, status: :ok, location: #season }
else
format.html { render :edit }
format.json { render json: #season.errors, status: :unprocessable_entity }
end
end
end
# DELETE /seasons/1
# DELETE /seasons/1.json
def destroy
#season.destroy
respond_to do |format|
format.html { redirect_to seasons_url, notice: 'Season was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_season
#season = Season.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def season_params
params.require(:season).permit(:season_name, :season_start, :season_end)
end
end
What am I doing wrong?
EDIT: Adding Schema.rb
# encoding: UTF-8
# This file is auto-generated from the current state of the database. Instead
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
#
# Note that this schema.rb definition is the authoritative source for your
# database schema. If you need to create the application database on another
# system, you should be using db:schema:load, not running all the migrations
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
# you'll amass, the slower it'll run and the greater likelihood for issues).
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20160729111417) do
create_table "danceclasses", force: :cascade do |t|
t.string "class_id", limit: 255
t.string "class_name", limit: 255
t.text "class_description", limit: 65535
t.integer "min_students", limit: 4
t.integer "max_students", limit: 4
t.string "category", limit: 255
t.datetime "start_date"
t.datetime "end_date"
t.integer "week_frequency", limit: 4
t.integer "day_frequency", limit: 4
t.string "start_time", limit: 255
t.string "end_time", limit: 255
t.integer "fee", limit: 4
t.string "level", limit: 255
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "season_classes", force: :cascade do |t|
t.integer "season_id", limit: 4
t.integer "danceclass_id", limit: 4
end
create_table "seasons", force: :cascade do |t|
t.string "season_name", limit: 255
t.datetime "season_start"
t.datetime "season_end"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "student_classes", force: :cascade do |t|
t.integer "student_id", limit: 4
t.integer "class_id", limit: 4
end
create_table "students", force: :cascade do |t|
t.string "first_name", limit: 255
t.string "last_name", limit: 255
t.string "student_id", limit: 255
t.datetime "date_of_birth"
t.text "notes", limit: 65535
t.string "gender", limit: 255
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "user_students", force: :cascade do |t|
t.integer "user_id", limit: 4
t.integer "student_id", limit: 4
end
create_table "users", force: :cascade do |t|
t.string "username", limit: 255
t.string "email", limit: 255
t.string "password", limit: 255
t.string "first_name", limit: 255
t.string "last_name", limit: 255
t.string "phone_number", limit: 255
t.datetime "date_of_birth"
t.string "street_1", limit: 255
t.string "street_2", limit: 255
t.string "city", limit: 255
t.string "state", limit: 255
t.string "zipcode", limit: 255
t.boolean "enabled"
t.boolean "is_admin"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
You need to change your has_many association properly.
class Season < ActiveRecord::Base
has_many :season_classes
has_many :danceclasses, through: :season_class
end
Hope this help you!
First of all the associations you have taken should be plural for has_many,
class Season < ActiveRecord::Base
has_many :season_classes
has_many :dance_classes, through: :season_classes
end
class Danceclass < ActiveRecord::Base
belongs_to :season
has_many :student_classes
has_many :students, through: :student_classes
end
class SeasonDanceclasses < ActiveRecord::Base
belongs_to :season
belongs_to :danceclass
end
Now, as you said that view is show page for season your season show action is,
class SeasonsController < ApplicationController
before_action :set_season, only: [:show, :edit, :update, :destroy]
def index
#seasons = Season.all
end
def show
end
end
Your show method contains #season variable but not #seasons, which was set in set_season action,
so app/views/seasons/show.html.erb is,
This is with your old association
<h2>Dance Classes Created</h2>
<% #season.danceclass.each do |danceclass| %>
-----------
----------
<% end %>
<p></p>
This is with changed associations
<h2>Dance Classes Created</h2>
<% #season.dance_classes.each do |danceclass| %>
-----------
----------
<% end %>
<p></p>
Related
I'm a beginner in rails and am making a card app. I have a user, card, and user_card models with a many to many, through relationship set up between the cards and users. My problem is that when I return the card table and try to include: the users I get an empty array. I've tried resetting the database but still nothing.
ActiveRecord::Schema.define(version: 2022_06_15_200100) do
create_table "cards", force: :cascade do |t|
t.string "name"
t.string "image"
t.string "text"
t.integer "level"
t.string "types"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.integer "quantity", default: 0
end
create_table "user_cards", force: :cascade do |t|
t.integer "user_id"
t.integer "card_id"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["card_id"], name: "index_user_cards_on_card_id"
t.index ["user_id"], name: "index_user_cards_on_user_id"
end
create_table "users", force: :cascade do |t|
t.string "username"
t.string "password_digest"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
class User < ApplicationRecord
has_secure_password
has_many :user_cards
has_many :cards, through: :user_cards
end
class Card < ApplicationRecord
has_many :user_cards
has_many :users, through: :user_cards
end
class UserCard < ApplicationRecord
belongs_to :user
belongs_to :card
end
controller
class CardsController < ApplicationController
wrap_parameters false
def create
card = Card.create(card_params)
if card.valid?
render json: card, status: :created, include: :users
else
render json:{errors: card.errors}
end
def index
card = Card.all
render json: card, include: :users
end
In order for the User.first.cards to work, you need to ensure the application is inserting data in the user_cards table.
You may check if there are any records in there by doing UserCard.all in your rails console.
Coming to the controller, after creating a card record, you have to assign it to a user record in order for the relationship to be established.
def create
card = Card.create(card_params)
if card.valid?
card.users << current_user # Or card.users << (any user object like) User.first
render json: card, status: :created, include: :users
else
render json:{errors: card.errors}
end
end
card.users << user object will create the necessary record in the user_cards table and you'll be able to access them using includes: :user
You may refer the examples given - here in the Rails API guide
I am trying to establish relationship between two tables in rails so
that I can share data between the two tables. However,am not able to
enter data into the operating tables. Any help would be highly appreciated.
#below are models#
class Location < ApplicationRecord
has_many :operatings
end
class Operating < ApplicationRecord
belongs_to :location
end
##below are my tables##
enable_extension "plpgsql"
create_table "locations", force: :cascade do |t|
t.string "country"
t.string "supra_region"
t.string "region"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "operatings", force: :cascade do |t|
t.string "operating_company_name"
t.string "address"
t.date "year_formed"
t.string "other_operational_countries"
t.string "about_company"
t.string "current_focus"
t.string "incumbent_irm_contractor"
t.string "irm_frame_agreements"
t.text "estimated_irm_budgets"
t.integer "location_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["location_id"], name: "index_operatings_on_location_id", using: :btree
end
add_foreign_key "operatings", "locations"
###below is my operating controller###
def create
#operating = Operating.new(op_company)
if #operating.save
flash[:success] = "A recorded has been successfully Saved"
redirect_to operatings_path
else
render 'new'
end
end
####routes####
resources :offshores, :index, :show, :new, :create, :destroy
resources :locations, :index, :show, :new, :create, :destroy
Try
class Operating < ApplicationRecord
belongs_to :location, :optional => true
end
belongs_to will check is the association present, you can debug by printing the Operating's errors
operating = Operating.create
operating.errors.messages
I'm quite new to rails/programming/web development, and this is the error that I'm getting:
ActiveModel::MissingAttributeError (can't write unknown attribute 'shopping_list_id')
I'm trying to save a shopping list object which is populated with Item objects after selecting specific Meal objects (with collection_check_box) and the associated Ingredient objects.
Looking through the localhost server logs, all the items are created correctly using the correct ingredients retrieved (and assigned to the current shopping list id) from the correct meal_ids - but when it comes to saving the actual shopping list I get the above error. Please see below for image of server log.
I've been stuck on this for a few days now and I've seen many posts with the same error but all seem to have quite different contexts to this issue.
Is it something to do with strong_parameters? Or are my associations wrong?
In my meals index.html.erb:
<%= form_for :shopping_list, url: shopping_lists_path do |f| %>
<%= collection_check_boxes :shopping_list, :meal_ids, Meal.all, :id, :name do |b|%>
<%= b.label class:"label-checkbox" do%>
<%=b.check_box + b.text%>
<%end%>
<% end %>
<%= f.submit "Create Shopping List" %>
<% end %>
My shopping_lists_controller:
def create
#shopping_list = ShoppingList.new(shopping_list_params)
#meals = Meal.where(id:[#shopping_list.meal_ids])
#meals.map do |meal|
meal.ingredients.map do |ingredient|
#shopping_list.items.build(name: ingredient.name, quantity: ingredient.quantity, unit: ingredient.unit, shopping_list_id: #shopping_list.id)
end
end
respond_to do |format|
if #shopping_list.save
format.html { redirect_to #shopping_list, notice: 'Shopping List was successfully created.' }
format.json { render :show, status: :created, location: #shopping_list }
else
format.html { render :new }
format.json { render json: #shopping_list.errors, status: :unprocessable_entity }
end
end
end
private
def set_shopping_list
#shopping_list = ShoppingList.find(params[:id])
end
def shopping_list_params
params.require(:shopping_list).permit(:name, {meal_ids: []})
end
My ShoppingList Model:
class ShoppingList < ApplicationRecord
has_many :items
has_many :meals
accepts_nested_attributes_for :meals
accepts_nested_attributes_for :items
end
My Item Model:
class Item < ApplicationRecord
belongs_to :shopping_list
end
My schema.rb:
create_table "ingredients", force: :cascade do |t|
t.integer "meal_id"
t.string "name"
t.float "quantity"
t.integer "unit"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["meal_id"], name: "index_ingredients_on_meal_id"
end
create_table "items", force: :cascade do |t|
t.integer "shopping_list_id"
t.string "name"
t.float "quantity"
t.integer "unit"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["shopping_list_id"], name: "index_items_on_shopping_list_id"
end
create_table "meals", force: :cascade do |t|
t.string "name"
t.string "description"
t.string "method"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "meal_image_file_name"
t.string "meal_image_content_type"
t.integer "meal_image_file_size"
t.datetime "meal_image_updated_at"
t.integer "diet"
end
create_table "shopping_lists", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Image of server log
The issue is that Meal model has belongs_to :shopping_list but it doesn't have column shopping_list_id.
So when you run
ShoppingList.create(meal_ids: ['1'])
Rails tries to create Meal model and link it back to the ShoppingList, but it can't since there is no such attribute and error tells you that ActiveModel::MissingAttributeError. To fix create a migration e.g.:
add_column :meals, :shopping_list_id, :integer
In the create method of shopping_lists_controller, you are using a new instance of shopping_list and using the id of that instance to create items. Since the new instance is not saved to the db, it will not have id. So you cannot use #shopping_list.id while creating items.
So either change
#shopping_list = ShoppingList.new(shopping_list_params)
to
#shopping_list = ShoppingList.create(shopping_list_params)
or do
#shopping_list = ShoppingList.new(shopping_list_params)
#shopping_list.save
You may also want to destroy this object if any exception is raised.
I've been trying to get the answer to this problem but without any luck. I guess it's an association problem and probably a rookie mistake (I'm one).
This is the functionality:
I need to create packs of beers for specific profiles (I know everything sounds fun with beers but it's killing me)
I have 3 models:
A beer model:
class Beer < ActiveRecord::Base
include PermissionsConcern
validates :name, presence: true
has_many :ratings
has_many :users, through: :ratings
has_many :packs
end
A profile model:
class Profile < ActiveRecord::Base
has_many :packs
end
A Pack model:
class Pack < ActiveRecord::Base
belongs_to :beer
belongs_to :profile
end
This is the packs_controller
class PacksController < ApplicationController
before_action :set_pack, only: [:show, :edit, :update, :destroy]
def index
#packs = Pack.all
end
def show
end
def edit
#beers = Beer.all #Implementación incompleta. Revisar Filtros
#profiles = Profile.all
end
def create
#pack = Pack.new(pack_params)
respond_to do |format|
if #pack.save
format.html { redirect_to #pack, notice: 'Pack was successfully created.' }
else
format.html { render :new }
end
end
end
def update
respond_to do |format|
if #pack.update(pack_params)
format.html { redirect_to #pack, notice: 'Pack was successfully updated.' }
else
format.html { render :edit }
end
end
end
...
private
def set_pack
#pack = Pack.find(params[:id])
end
def pack_params
params.require(:pack).permit(:delivery_date, :profile_id, :beer_id, :status)
end
end
With this configuration I have the following situation:
in the Index view I do
#packs.each do |p|
p.beer.name #works fine
p.profile.name #brings an "undefined method `name' for nil:NilClass" message
end
In the show view I do:
#pack.beer.name #works fine.
#pack.profile.name #WORKS FINE ALSO
I tried to do it in the console and the results are the same:
Pack.last.profile.name # works fine
Pack.all # works and shows the profile_id correctly.
packs = Pack.all
packs.each do |p|
print p.beer.name #works fine
print p.profile.name #nil class again
end
Just in case I'm including the Schema:
create_table "beers", force: :cascade do |t|
t.string "name", limit: 255
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "beer_type", limit: 255
end
create_table "packs", force: :cascade do |t|
t.date "delivery_date"
t.integer "profile_id", limit: 4
t.integer "beer_id", limit: 4
t.integer "status", limit: 4
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "packs", ["beer_id"], name: "index_packs_on_beer_id", using: :btree
add_index "packs", ["profile_id"], name: "index_packs_on_profile_id", using: :btree
create_table "profiles", force: :cascade do |t|
t.string "ibu_range", limit: 255
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "name", limit: 255
end
add_foreign_key "packs", "beers"
add_foreign_key "packs", "profiles"
end
I tried to explain the situation as detailed as possible. Can anyone help me understand what I'm doing wrong? Thanks!!!
Some of the packs may not have profile?
Since you are using console, try this:
Pack.all.select{|item| item.profile.nil?}.size
If size>0 and you don't want this, then please add validates :profile, presence: true.
I am new to rails, and cannot figure out that why do I get the error specified above when I try to create a new application after login.
Also, while I was looking at solutions online, I found there was something wrong with the foreign key. therefore, I removed the foreign key and added it again using migration. However, the schema.rb file that is shown below does not show an index, but does show Student_id column.
Questions :
Should creation of has_one and belongs_to association require one to mention it in routes.rb as well . ( I read online it does require, but why ? )
How to decide where to place belongs_to and has_one.
How to find out where the above error is generated from ?
Model Student ( created using devise )
class Student < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_one :student_application
end
StudentApplication ( Generate using scaffold)
class StudentApplication < ActiveRecord::Base
belongs_to :Student
end
routes.rb
Rails.application.routes.draw do
resources :student_applications
devise_for :students
root to: "student_applications#index"
end
In the controller student_application_controller.rb
def new
##student_application = StudentApplication.new
#student_application = current_student.build_student_application()
end
def create
##student_application = StudentApplication.new(student_application_params)
##new_student = Student.find(params[:id])
#student_application = current_student.create_student_application(student_application_params)
respond_to do |format|
if #student_application.save
format.html { redirect_to #student_application, notice: 'Student application was successfully created.' }
format.json { render :show, status: :created, location: #student_application }
else
format.html { render :new }
format.json { render json: #student_application.errors, status: :unprocessable_entity }
end
end
end
private
def student_application_params
params.require(:student_application).permit(:Student_id, :name, :phone, :email_id, :gpa)
end
schema.rb
create_table "student_applications", force: :cascade do |t|
t.string "name"
t.string "phone"
t.string "email_id"
t.decimal "gpa"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "Student_id"
end
create_table "students", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "students", ["email"], name: "index_students_on_email", unique: true
add_index "students", ["reset_password_token"], name: "index_students_on_reset_password_token", unique: true
end