rubysinatranomethoderrorruby-datamapper

Sinatra: NoMethodError


Whole source code here

I think I have a logic error in program flow, which returns NoMethodError

First, a piece of code which causes error.

<input id="#identity" type="number" name="journal[identity]" value="<%= @journal.identity  unless @journal.identity.nil? %>" />


#Error Text
NoMethodError at /profile
undefined method `identity' for nil:NilClass
file: journal_form.erb location: block in singleton class line: 2 

The code inside the input tag is the exact code piece which described in error text.

My program flow is like that.

  1. User logs in
  2. If authentication is successful, he/she will be redirected to /profile page
  3. According to their roles/privileges they will see different content inside main area in '/profile'. Content is database

1 is ok. Users can log in and out without problem. For 2nd step, code is like that

#profile.erb
<% if session[:user].role == 1 %>
    <%= erb :assign_doctor %>
<% elsif session[:user].role == 2 %>
    <%= erb :journal_form %>
<% elsif session[:user].role == 3 %>
    <pre>
        Silence!        
    </pre>
<% elsif session[:user].role == 4 %>
    <%= erb :doctor_screen %>

<% end %>

the 'journal_form.erb' file in second condition.

<input id="#identity" type="number" name="journal[identity]" 
        value="<%= @journal.identity  unless @journal.identity.nil? %>" />

.... # some other attributes like that.

<% if session[:user].role == 1 %>
    <% if journal.viewed == false %>
<input id="#assigned_doctor" type = "text" name="journal[assigned_doctor]" />
    <% else %>
<input id="#assigned_doctor" type = "text" name="journal[assigned_doctor]" value="<%= @journal.assigned_doctor  unless @journal.assigned_doctor.nil? %>" />
    <% end %>

I've also created CRUD resources for journal model entries (in other file). And without yielding CRUD views into profile they work ok.

Maybe problem is, the profile is not aware of the context passed into it, so it responses like that. But have no any idea how to fix it.

I can add more code, if you want.

In summation:

When @journal == nil why does <%=@journal.identity unless @journal.identity.nil?%> return undefined method 'identity' for nil:NilClass?

Below there are some helpful resources:

in user.rb (contains 3 classes/models) in the same directory with main.rb.

# model declerations end here
DataMapper.finalize

module JournalHelpers
    def find_journals
        @journals = Journal.all
    end

    def find_journal
        Journal.get(params[:id])
    end

    def create_journal
        @journal = Journal.create(params[:journal])
    end
end

helpers JournalHelpers

get '/journals' do 
    find_journals
    erb :journals
end

#new
get '/journals/new' do
    #protected!
    @journal = Journal.new
    erb :new_journal
end


#show
get '/journals/:id' do
    @journal = find_journal
    erb :show_journal
end

#create
post '/journals' do
    #protected!
  flash[:notice]= "Journal was succesfull posted" if create_journal
  redirect to("/journals/#{@journal.id}")
end

#edit
get '/journals/:id/edit' do
    #protected!
    @journal = find_journal
    erb :edit_journal
end

#put/update

put '/journals/:id' do
    #protected!
    journal = find_journal
    if journal.update(params[:journal])
        flash[:notice] = "Journal successfully updated"
    end
    redirect to("/journals/#{journal.id}")
end

Program structure

├── assets
│   ├── css
│   │   ├── application.css
│   │   ├── jquery-ui.min.css
│   │   └── main.css
│   ├── images
│   │   ├── loader.gif
│   │   └── nurse_shshsh.jpeg
│   └── js
│       ├── application.js
│       ├── jquery.min.js
│       └── jquery-ui.min.js
├── main.rb
├── user.rb
├── users.db
└── views
    ├── about.erb
    ├── assign_doctor.erb
    ├── contact.erb
    ├── doctor_screen.erb
    ├── edit_journal.erb
    ├── home.erb
    ├── journal_form.erb
    ├── journals.erb
    ├── layout.erb
    ├── leftcolumn.erb
    ├── login.erb
    ├── nav.erb
    ├── new_journal.erb
    ├── notifications.erb
    ├── profile.erb
    └── show_journal.erb

Checking for if journal is nil.

get '/profile' do 
    if !authorized?
        redirect to('/login')
    else
        puts "nihil" if @journal.nil?
        erb :profile
    end
end

server log

127.0.0.1 - - [29/Jun/2015:22:35:33 +0500] "GET /profile HTTP/1.1" 302 - 0.0029
127.0.0.1 - - [29/Jun/2015:22:35:33 +0500] "GET /login HTTP/1.1" 200 212 0.0024
127.0.0.1 - - [29/Jun/2015:22:35:42 +0500] "POST /login HTTP/1.1" 303 - 0.0167
nihil
127.0.0.1 - - [29/Jun/2015:22:35:43 +0500] "GET /profile HTTP/1.1" 200 1047 0.0106

@journal is nil.


Solution

  • It looks to me that your code are relying on the fact that there is a @journal field set. (And whose journal is this anyway?) It is certainly not being set in main.rb. You should get the data you need in the get '/profile' block. Something along the lines of:

    get '/profile' do
      if !authorized?
        redirect to('/login')
      else
        @journal = Journal.get(params[:id])
        erb :profile
      end
    end
    

    There are various ways to do this. It is normally good to avoid any shared state between calls and instead getting all needed data in each specific request. (Data can still be reused as in your JournalHelper module.) If database access becomes a bottle neck the best way forward is usually to introduce a cache in front of the database or the web server.