Reputation: 31
I am vaguely following http://guides.rubyonrails.org/getting_started.html, Part 6.
Using Rails v 4.1.8 SQLite DB
I get this error after adding a second model:
NoMethodError in Pages#show
Showing M:/ICT/Rails/Salacity/app/views/pages/show.html.erb where line
24 raised:
undefined method `links' for #
Extracted source (around line #24)
Links
<% @page.links.each do |link| %>ID: <%= link.child__id %>
Rails.root: M:/ICT/Rails/Salacity Application Trace | Framework Trace | Full Trace
app/views/pages/show.html.erb:24:in `_app_views_pages_show_html_erb___283878207_51684456'
This is app/views/pages/show.html.erb
<p id="notice"><%= notice %></p>
<p>
<strong>Page:</strong>
<%= @page.page_id %>
</p>
<p>
<strong>Body:</strong>
<%= @page.body %>
</p>
<p>
<strong>Branch:</strong>
<%= @page.branch_id %>
</p>
<p>
<strong>Location:</strong>
<%= @page.location_id %>
</p>
<h2>Links</h2>
<% @page.links.each do |link| %>
<p>
<strong>ID:</strong>
<%= link.child__id %>
</p>
<p>
<strong>Body:</strong>
<%= link.body %>
</p>
<% end %>
<h2>Add a link:</h2>
<%= form_for([@page, @page.links.build]) do |f| %>
<p>
<%= f.label :page_id %><br>
<%= f.text_field :page_id %>
</p>
<p>
<%= f.label :child_id %><br>
<%= f.text_area :child_id %>
</p>
<p>
<%= f.label :order %><br>
<%= f.number_field :order %>
</p>
<p>
<%= f.label :body %><br>
<%= f.text_area :body %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
<%= link_to 'Edit', edit_page_path(@page) %> |
<%= link_to 'Back', pages_path %>
PagesController
class PagesController < ApplicationController
before_action :set_page, only: [:show, :edit, :update, :destroy]
# GET /pages
# GET /pages.json
def index
@pages = Page.all
end
# GET /pages/1
# GET /pages/1.json
def show
@page = Page.find(show_params)
end
# GET /pages/new
def new
@page = Page.new
end
# GET /pages/1/edit
def edit
@page = Page.find(params[:id])
end
# POST /pages
# POST /pages.json
def create
@page = Page.new(page_params)
respond_to do |format|
if @page.save
format.html { redirect_to @page, notice: 'Page was successfully created.' }
format.json { render :show, status: :created, location: @page }
else
format.html { render :new }
format.json { render json: @page.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /pages/1
# PATCH/PUT /pages/1.json
def update
respond_to do |format|
if @page.update(page_params)
format.html { redirect_to @page, notice: 'Page was successfully updated.' }
format.json { render :show, status: :ok, location: @page }
else
format.html { render :edit }
format.json { render json: @page.errors, status: :unprocessable_entity }
end
end
end
# DELETE /pages/1
# DELETE /pages/1.json
def destroy
@page = Page.find(params[:id])
@page.destroy
respond_to do |format|
format.html { redirect_to pages_url, notice: 'Page was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_page
@page = Page.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def page_params
params.require(:page).permit(:page_id, :body, :branch_id, :location_id)
end
def show_params
params.require(:id)
end
end
LinksController
class LinksController < ApplicationController
before_action :set_link, only: [:show, :edit, :update, :destroy]
# GET /links
# GET /links.json
def index
@links = Link.all
end
# GET /links/1
# GET /links/1.json
def show
end
# GET /links/new
def new
@link = Link.new
end
# GET /links/1/edit
def edit
end
# POST /links
# POST /links.json
=begin
def create
@link = Link.new(link_params)
respond_to do |format|
if @link.save
format.html { redirect_to @link, notice: 'Link was successfully created.' }
format.json { render :show, status: :created, location: @link }
else
format.html { render :new }
format.json { render json: @link.errors, status: :unprocessable_entity }
end
end
end
=end
def create
@page = Page.find(params[:page_id])
@link = @page.links.create(link_params)
redirect_to page_path(@page)
end
# PATCH/PUT /links/1
# PATCH/PUT /links/1.json
def update
respond_to do |format|
if @link.update(link_params)
format.html { redirect_to @link, notice: 'Link was successfully updated.' }
format.json { render :show, status: :ok, location: @link }
else
format.html { render :edit }
format.json { render json: @link.errors, status: :unprocessable_entity }
end
end
end
# DELETE /links/1
# DELETE /links/1.json
def destroy
@link.destroy
respond_to do |format|
format.html { redirect_to links_url, notice: 'Link was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_link
@link = Link.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def link_params
params.require(:link).permit(:page_id, :child_id, :order, :body)
end
end
Class Page has_many :links and class Link belongs_to :page Migrations are all up Links table exists in DB Not sure where else to look!
Thanks in advance
edit: I also get this error
ActiveRecord::StatementInvalid in Pages#show
Showing M:/ICT/Rails/Salacity/app/views/pages/show.html.erb where line
24 raised:
SQLite3::SQLException: no such column: links.page_id: SELECT "links".* FROM "links" WHERE "links"."page_id" = ?
Extracted source (around line #24):
Links
<% @page.links.each do |link| %>ID: <%= link.child__id %>
Rails.root: M:/ICT/Rails/Salacity Application Trace | Framework Trace | Full Trace
app/views/pages/show.html.erb:24:in `_app_views_pages_show_html_erb___283878207_50250936'
db/migrate/create_links.rb
class CreateLinks < ActiveRecord::Migration
def change
create_table :links do |t|
t.text :page_id
t.text :child_id
t.integer :order
t.text :body
t.references :page, foreign_key: true, index: true
t.timestamps
end
end
end
and 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: 20150707195306) do
# Could not dump table "branches" because of following NoMethodError
# undefined method `[]' for nil:NilClass
# Could not dump table "keywords" because of following NoMethodError
# undefined method `[]' for nil:NilClass
# Could not dump table "links" because of following NoMethodError
# undefined method `[]' for nil:NilClass
# Could not dump table "locations" because of following NoMethodError
# undefined method `[]' for nil:NilClass
# Could not dump table "pages" because of following NoMethodError
# undefined method `[]' for nil:NilClass
end
Upvotes: 3
Views: 2572
Reputation: 31
Bit of a wild goose chase this one I think, 'show' is now displaying after renaming the column on the correct DB. Thanks for the assistance guys
Upvotes: 0
Reputation: 76784
I'll get into specifics in a second (you could improve your code a lot).
The error seems to be that your links
method is non existent.
This could be for a number of reasons, I'll describe how to make sure it's fixed:
#app/models/page.rb
class Page < ActiveRecord::Base
has_many :links
end
#app/models/link.rb
class Link < ActiveRecord::Base
belongs_to :page
end
This is a standard has_many/belongs_to
relationship:
As you can see from the diagram above, this means you have to have the appropriate foreign_keys
set up in your links
table:
#links
id | page_id | etc | etc | etc
You need to make sure you have page_id
as either an integer
or reference
in your table:
$ rails g migration ChangePageIDLinks
#db/migrate/change_page_id_links__________.rb
class ChangePageIdLinks
def change
change_column :links, :page_id, :integer
end
end
$ rake db:migrate
This will ensure your links
database has the correct reference.
This means that each time you use @page.links
, it will have a method to call. Whether you've set it up correctly is what we'll look at next:
Find
The main reason for noMethod
errors in Rails (I was originally going to write this) is because you're calling a method on a non-existent variable.
Most developers are thrown by this at first (they think the "method" is the error). In Rails, when you don't have a variable that's populated, Ruby will assign it to the Nil:NilClass
class.
This means the variable will actually be present, just not populated. Thus, any methods you call on it will not be existent either.
I believe you'll have this type of error too:
def show
@page = Page.find(show_params) #-> Not necessary, although not wrong ^_^
end
Use this for your pages
controller:
#app/controllers/pages_controller.rb
class PagesController < ApplicationController
before_action :set_page, only: [:show, :edit, :update, :destroy]
# GET /pages
# GET /pages.json
def index
@pages = Page.all
end
# GET /pages/1
# GET /pages/1.json
def show
end
# GET /pages/new
def new
@page = Page.new
end
# GET /pages/1/edit
def edit
end
# POST /pages
# POST /pages.json
def create
@page = Page.new page_params
respond_to do |format|
if @page.save
format.html { redirect_to @page, notice: 'Page was successfully created.' }
format.json { render :show, status: :created, location: @page }
else
format.html { render :new }
format.json { render json: @page.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /pages/1
# PATCH/PUT /pages/1.json
def update
respond_to do |format|
if @page.update(page_params)
format.html { redirect_to @page, notice: 'Page was successfully updated.' }
format.json { render :show, status: :ok, location: @page }
else
format.html { render :edit }
format.json { render json: @page.errors, status: :unprocessable_entity }
end
end
end
# DELETE /pages/1
# DELETE /pages/1.json
def destroy
@page.destroy
respond_to do |format|
format.html { redirect_to pages_url, notice: 'Page was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_page
@page = Page.find params[:id]
end
def page_params
params.require(:page).permit(:link_id, :body, :branch_id, :location_id)
end
end
This should resolve the problem in your show
view
--
Loop
Finally, another potential error I thought was causing exception:
<% @page.links.each do |link| %>
I've had this happen a number of times - Ruby/Rails will run the loop regardless of whether @page.links
is populated. If it isn't, the error itself will not be from the loop, but the code you're trying to run inside it.
If your loop has the potentiality of having nil data, you need to make it conditional:
<% if @page.links.any? %>
<% @page.links.each do .... %>
<% end %>
Upvotes: 0
Reputation: 1601
Change your migration file like this
db/migrate/timestamp_create_links.rb
class CreateLinks < ActiveRecord::Migration
def change
create_table :links do |t|
t.integer :child_id
t.integer :order
t.text :body
t.references :page, index: true
t.timestamps
end
end
end
Upvotes: 0