Varis Darasirikul
Varis Darasirikul

Reputation: 4187

Why can't I save data into the database using Sinatra and PostgreSQL?

I created my database in PostgreSQL and migrated it. When I tried to save new data into it I got this error:

enter image description here

This is my code:

My layout:

<form method="post" action="/signup">
                    <div class="form-group">
                        <label>Username</label>
                        <input type="text" class="form-control" placeholder="Name" name="user[username]">
                    </div>
                    <div class="form-group">
                        <label>Email address</label>
                        <input type="email" class="form-control" placeholder="Email" name="user[email]">
                    </div>
                    <div class="form-group">
                        <label>Password</label>
                        <input type="password" class="form-control" placeholder="Password" name="user[password]">
                    </div>
                    <div class="form-group">
                        <label>Confirm Password</label>
                        <input type="password" class="form-control" placeholder="Confirm Password" name="user[confirm_password]">
                    </div>
                    <button type="submit" class="btn btn-info">Sign up</button>
                </form>

My controller:

post '/signup' do
    user = User.new(params[:user])
    user.create_user

end

My model:

require 'bcrypt'

class User < ActiveRecord::Base
    include BCrypt
    # This is Sinatra! Remember to create a migration!
    validates :email, :format => { :with => /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i ,
    :message => "Email wrong format" }
    validates :email, uniqueness: true

    def initialize(signup)
        #@signup = signup
        @username = signup["username"]
        @email = signup["email"]
        @password = signup["password"]
    end

    def test
        p @signup
    end

    def create_user
        p_p = Password.create(@password)
        p_h ||= Password.new(p_p)
        user_hash = {:username => @username,:email => @email, :encrypted_password => p_h}

        User.create(user_hash)

    end

end

Full back trace

/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activerecord-4.2.5.1/lib/active_record/transactions.rb in clear_transaction_record_state
      @_start_transaction_state[:level] = (@_start_transaction_state[:level] || 0) - 1
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activerecord-4.2.5.1/lib/active_record/transactions.rb in ensure in rollback_active_record_state!
      clear_transaction_record_state
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activerecord-4.2.5.1/lib/active_record/transactions.rb in rollback_active_record_state!
      clear_transaction_record_state
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activerecord-4.2.5.1/lib/active_record/transactions.rb in save
      rollback_active_record_state! do
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/activerecord-4.2.5.1/lib/active_record/persistence.rb in create
          object.save
/Sites/nextAcademy/quora_clone/code/app/models/user.rb in create_user
        return User.create(user_hash)
/Sites/nextAcademy/quora_clone/code/app/controllers/static.rb in block in <top (required)>
    "#{user.create_user}"
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in call
          proc { |a,p| unbound_method.bind(a).call }
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in block in compile!
          proc { |a,p| unbound_method.bind(a).call }
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in []
            route_eval { block[*args] }
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in block (3 levels) in route!
            route_eval { block[*args] }
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in route_eval
      throw :halt, yield
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in block (2 levels) in route!
            route_eval { block[*args] }
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in block in process_route
        block ? block[self, values] : yield(self, values)
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in catch
      catch(:pass) do
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in process_route
      catch(:pass) do
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in block in route!
          returned_pass_block = process_route(pattern, keys, conditions) do |*args|
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in each
        routes.each do |pattern, keys, conditions, block|
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in route!
        routes.each do |pattern, keys, conditions, block|
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in block in dispatch!
        route!
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in block in invoke
      res = catch(:halt) { yield }
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in catch
      res = catch(:halt) { yield }
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in invoke
      res = catch(:halt) { yield }
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in dispatch!
      invoke do
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in block in call!
      invoke { dispatch! }
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in block in invoke
      res = catch(:halt) { yield }
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in catch
      res = catch(:halt) { yield }
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in invoke
      res = catch(:halt) { yield }
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in call!
      invoke { dispatch! }
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in call
      dup.call!(env)
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/session/abstract/id.rb in context
          status, headers, body = app.call(env)
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/session/abstract/id.rb in call
          context(env)
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-protection-1.5.3/lib/rack/protection/xss_header.rb in call
        status, headers, body = @app.call(env)
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-protection-1.5.3/lib/rack/protection/path_traversal.rb in call
        app.call env
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-protection-1.5.3/lib/rack/protection/json_csrf.rb in call
        status, headers, body = app.call(env)
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-protection-1.5.3/lib/rack/protection/base.rb in call
        result or app.call(env)
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-protection-1.5.3/lib/rack/protection/base.rb in call
        result or app.call(env)
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-protection-1.5.3/lib/rack/protection/frame_options.rb in call
        status, headers, body        = @app.call(env)
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/logger.rb in call
      @app.call(env)
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in call
      env['sinatra.commonlogger'] ? @app.call(env) : super
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/head.rb in call
    status, headers, body = @app.call(env)
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/methodoverride.rb in call
      @app.call(env)
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/show_exceptions.rb in call
      @app.call(env)
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in call
      result, callback = app.call(env), env['async.callback']
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in call
      @stack.call(env)
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in block in call
        synchronize { prototype.call(env) }
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in synchronize
          yield
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in call
        synchronize { prototype.call(env) }
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/lint.rb in _call
      status, headers, @body = @app.call(env)
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/lint.rb in call
      dup._call(env)
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/showexceptions.rb in call
      @app.call(env)
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/commonlogger.rb in call
      status, header, body = @app.call(env)
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/sinatra-1.4.6/lib/sinatra/base.rb in call
        call_without_check(env)
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/shotgun-0.9.1/lib/shotgun/loader.rb in proceed_as_child
      status, headers, body = assemble_app.call(@env)
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/shotgun-0.9.1/lib/shotgun/loader.rb in call!
        proceed_as_child
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/shotgun-0.9.1/lib/shotgun/loader.rb in call
      dup.call!(env)
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/shotgun-0.9.1/lib/shotgun/favicon.rb in call
        app.call(env)
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/shotgun-0.9.1/lib/shotgun/static.rb in call
        @app.call(env)
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/urlmap.rb in block in call
        return app.call(env)
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/urlmap.rb in each
      @mapping.each do |host, location, match, app|
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/urlmap.rb in call
      @mapping.each do |host, location, match, app|
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/builder.rb in call
      to_app.call(env)
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/thin-1.6.4/lib/thin/connection.rb in block in pre_process
        response = @app.call(@request.env)
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/thin-1.6.4/lib/thin/connection.rb in catch
      catch(:async) do
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/thin-1.6.4/lib/thin/connection.rb in pre_process
      catch(:async) do
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/thin-1.6.4/lib/thin/connection.rb in process
        post_process(pre_process)
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/thin-1.6.4/lib/thin/connection.rb in receive_data
      process if @request.parse(data)
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/eventmachine-1.0.8/lib/eventmachine.rb in run_machine
          run_machine
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/eventmachine-1.0.8/lib/eventmachine.rb in run
          run_machine
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/thin-1.6.4/lib/thin/backends/base.rb in start
          EventMachine.run(&starter)
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/thin-1.6.4/lib/thin/server.rb in start
      @backend.start { setup_signals if @setup_signals }
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/rack-1.6.4/lib/rack/handler/thin.rb in run
        server.start
/Users/manjarb/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/shotgun-0.9.1/bin/shotgun in <top (required)>
server.run app, options do |inst|
/Users/manjarb/.rbenv/versions/2.2.3/bin/shotgun in load
load Gem.bin_path('shotgun', 'shotgun', version)
/Users/manjarb/.rbenv/versions/2.2.3/bin/shotgun in <main>
load Gem.bin_path('shotgun', 'shotgun', version)

Does anyone know why this happended?

Upvotes: 0

Views: 502

Answers (2)

Martin Konecny
Martin Konecny

Reputation: 59681

Your problem is that your are extending the ActiveRecord::Base class, and overwriting it's constructor. Therefore several attributes that the ActiveRecord::Base relies on aren't initialized. Try adding super() into your constructor like so:

def initialize(signup)
    super()
    #@signup = signup
    @username = signup["username"]
    @email = signup["email"]
    @password = signup["password"]
end

Alternatively, remove the constructor completely and pass in the signup hash into the create_user method.

Upvotes: 1

AndyV
AndyV

Reputation: 3741

Is there a reason (other than lack of familiarity) not to use ActiveRecord callbacks? I think your solution could be considerably simpler if you let ActiveRecord do it's thing...

class User < ActiveRecord::Base
  attr_accessor :password

  validates :username, presence: true, uniqueness: true
  validates :email, format: { with: /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i, message: 'Invalid email format' },
                    uniqueness: true,
                    presence: true
  validates :encrypted_password, presence: true

  before :validation, :encrypt_password, if: :password_present?

  private

  def password_present?
    !password.nil? && !password.length.zero?
  end

  def encrypt_password
    self.encrypted_password = Password.new(password)
  end
end

In the example above, the "before :validation" line tells active record to call the encrypt_password method before validations are executed, but only if the password has been supplied. In that case it will assign the encrypted_password attribute a new Password based on the caller-supplied 'password' value.

Note that the code assumes that the password is not persisted to the database (only the encrypted_password is saved). If there is no db-backed password column you'll need to explicitly expose a password attribute for this to work. You've essentially worked around that via the @password instance variable in your code.

With a class like the one suggested, your controller would become

post '/signup' do
  user = User.create(params[:user])
end

Upvotes: 1

Related Questions