Why are my json attributes bouncing off in POST in Sinatra? - json

I hope someone can share their knowledge with me. I have a small Sinatra app that I want to POST json data to it. The record is being created, thankfully, but none of the attributes make it. I've read several JSON examples using curl but they all yield the same result. So it makes me think it's my model. I can create records using tux fine so perhaps it's not my model.
curl command:
curl -XPOST -H "Content-Type: application/json"
"localhost:4567/date" -d
'{ "post": { "title": "different tile here"}}'
curl output:
=> {"id":13,"title":null,"body":null,"created_at":"2014-04-21T18:13:53Z",
"updated_at":"2014-04-21T18:13:53Z"}
sinatra output:
[2014-04-27T20:03:48.035710 #45360] DEBUG -- : (0.1ms) commit transaction
127.0.0.1 - - [27/Apr/2014 20:03:48] "POST /date HTTP/1.1" 200 - 0.0181
{"post":{"title":"different tile here"}}
D, [2014-04-27T20:09:32.614274 #45360] DEBUG -- : (0.1ms) begin transaction
D, [2014-04-27T20:09:32.615917 #45360] DEBUG -- : SQL (0.4ms) INSERT INTO "posts" ("created_at", "updated_at") VALUES (?, ?) [["created_at", 2014-04-28 01:09:32 UTC], ["updated_at", 2014-04-28 01:09:32 UTC]]
D, [2014-04-27T20:09:32.617656 #45360] DEBUG -- : (1.5ms) commit transaction
D, [2014-04-27T20:09:32.617852 #45360] DEBUG -- : (0.1ms) begin transaction
D, [2014-04-27T20:09:32.618132 #45360] DEBUG -- : (0.0ms) commit transaction
127.0.0.1 - - [27/Apr/2014 20:09:32] "POST /date HTTP/1.1" 200 - 0.0070
D, [2014-04-27T20:09:57.796909 #45360] DEBUG -- : Post Load (0.3ms) SELECT "posts".* FROM "posts" ORDER BY created_at DESC
127.0.0.1 - - [27/Apr/2014 20:09:57] "GET / HTTP/1.1" 200 2149 0.0128
app.rb
require 'sinatra'
require 'sinatra/activerecord'
require './environments'
require 'sinatra/flash'
require 'sinatra/redirect_with_flash'
require 'json'
class Post < ActiveRecord::Base
end
post "/posts" do
#post = Post.new(params[:post])
if #post.save
redirect "posts/#{#post.id}"
else
erb :"posts/create"
end
end
post '/date', :provides => 'json' do
data = JSON.parse(request.body.read)
json_data = data.to_json
content_type :json
##post = Post.new(params)
#post = Post.create(
title: data[:title]
body: data[:body]
)
if #post.save
#post.to_json
else
halt 500
end
end
get "/posts/create" do
#title = "Create post"
#post = Post.new
erb :"posts/create"
end
get "/posts/:id" do
#post = Post.find(params[:id])
#title = #post.title
erb :"posts/view"
end
get "/" do
#posts = Post.order("created_at DESC")
#title = "Welcome."
erb :"posts/index"
end
Gemfile
source 'https://rubygems.org'
ruby "2.0.0"
gem "sinatra"
gem 'activerecord', '4.0.4'
gem "sinatra-activerecord"
gem 'sinatra-flash'
gem 'sinatra-redirect-with-flash'
gem 'json'
group :development do
gem 'sqlite3'
gem "tux"
end
group :production do
gem 'pg'
end
environments.rb
configure :development do
set :database, 'sqlite3:///dev.db'
set :show_exceptions, true
end
configure :production do
db = URI.parse(ENV['DATABASE_URL'] || 'postgres:///localhost/mydb')
ActiveRecord::Base.establish_connection(
adapter: db.scheme == 'postgres' ? 'postgresql' : db.scheme,
host: db.host,
username: db.user,
password: db.password,
database: db.path[1..-1],
encoding: 'utf9'
)
end
I've left off my layout files since I'm testing this POST via this rudimentary API. I've bounced around the few examples of Sinatra API's on the web and don't know what I'm not seeing. What am I overlooking here? It's almost like Strong Parameters in Rails 4, but if so why does tux allow me to create records? thanx, sam

Related

Rails invalid hash password authenticates in ruby console but after reopening it doesn't. Why?

I am following [lynda.com's Ruby on Rails 5 Essential Training][1] and am very stuck when building the login system.
The issue is the database seems to be holding a different hash to what rails is using. I have looked all over for reasons and fixes and I understand that the stored hash and the one rails runs are different but why and how can I fix this?
I have added:
bcrypt 3.1.11 gem installed password_digest column in table
has_secure_password to correct model file
I have migrated down and back up again to see if there are issues with the table.
The password stored in the database is hashed - password_digest: $2a$10$AMHXZBl/zXQ9yHOR7uBSiOdsGloArDkxO
I have even followed these steps in the Ruby console:
user.password = 'password'
user.password_confirmation = 'password'
user.save
user.authenticate('password')
The password saves and the authentication brings up the correct entry but it does not match after rerunning the console or using the login page on rails server.
I get this error each time:
BCrypt::Errors::InvalidHash (invalid hash):
app/controllers/cms_access_controller.rb:16:in `attempt_login'
and invalid hash error in the browser gets stuck here:
found_user = CmsUser.where(:username => params[:username]).first
if found_user
authorized_user = found_user.authenticate(params[:password])
end
end
Here is the log from rails:
Started POST "/cms_access/attempt_login" for 127.0.0.1 at 2018-01-02 17:59:18 +0800
Processing by CmsAccessController#attempt_login as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"YP2tiHyRfDhJhhuF+PPM0D+hA+6BMJW5YmTyZyLpT6nXs4NdhGyihVKZpoMaRl0oUsobnr6x5bYGBR75+huUjg==", "username"=>"username", "password"=>"[FILTERED]", "commit"=>"Login"}
[1m[36mCmsUser Load (0.4ms)[0m [1m[34mSELECT `cms_users`.* FROM `cms_users` WHERE `cms_users`.`username` = 'username' ORDER BY `cms_users`.`id` ASC LIMIT 1[0m
Completed 500 Internal Server Error in 9ms (ActiveRecord: 0.4ms)
BCrypt::Errors::InvalidHash (invalid hash):
app/controllers/cms_access_controller.rb:16:in `attempt_login'
Full irb code as follows:
irb(main):001:0> u = CmsUser.first
(0.4ms) SET NAMES utf8, ##SESSION.sql_mode = CONCAT(REPLACE(REPLACE(REPLACE(##sql_mode, 'STRICT_TRANS_TABLES', ''), 'STRICT_ALL_TABLES', ''), 'TRADITIONAL', ''), ',NO_AUTO_VALUE_ON_ZERO'), ##SESSION.sql_auto_is_null = 0, ##SESSION.wait_timeout = 2147483
CmsUser Load (0.2ms) SELECT `cms_users`.* FROM `cms_users` ORDER BY `cms_users`.`id` ASC LIMIT 1
=> #<CmsUser id: 1, first_name: "first name", last_name: "last name", email: "email", username: "username", password_digest: nil, created_at: "2018-01-02 14:48:42", updated_at: "2018-01-02 14:48:42">
irb(main):002:0> u.password = "password"
=> "password"
irb(main):003:0> u.password_confirmation = "password"
=> "password"
irb(main):004:0> u.save
(0.3ms) BEGIN
SQL (0.4ms) UPDATE `cms_users` SET `password_digest` = '$2a$10$gKAyDPTNzg.7Xnd7uatzuu0VWZNH6zGPA653RZ.5THB2Rziax1fyC', `updated_at` = '2018-01-02 14:50:29' WHERE `cms_users`.`id` = 1
(1.1ms) COMMIT
=> true
irb(main):005:0> u.authenticate("password")
=> #<CmsUser id: 1, first_name: "first name", last_name: "last name", email: "email", username: "username", password_digest: "$2a$10$gKAyDPTNzg.7Xnd7uatzuu0VWZNH6zGPA653RZ.5THB...", created_at: "2018-01-02 14:48:42", updated_at: "2018-01-02 14:50:29">
After running rails server and attempting login:
Started POST "/cms_access/attempt_login" for 127.0.0.1 at 2018-01-02 22:52:01 +0800
Processing by CmsAccessController#attempt_login as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"qF/U+46QhGZHYuEbfPTStRxryPpp0hIEt1TQIRVE5bgfEfoudm1a21x9XB2eQUNNcQDQilZTYgvTNTy/zbY+nw==", "username"=>"username", "password"=>"[FILTERED]", "commit"=>"Login"}
CmsUser Load (0.4ms) SELECT `cms_users`.* FROM `cms_users` WHERE `cms_users`.`username` = 'username' ORDER BY `cms_users`.`id` ASC LIMIT 1
Completed 500 Internal Server Error in 11ms (ActiveRecord: 0.8ms)
BCrypt::Errors::InvalidHash (invalid hash):
app/controllers/cms_access_controller.rb:16:in `attempt_login'
Try to following sign in action like below
found_user = CmsUser.find_by(:username => params[:session][:username].downcase)
if found_user && found_user.authenticate(params[:session][:password])
#=> code to be here
else
#=> code to be here
end
Hope to help

rails 5 api returns 301 from PORO

I have a Rails 5.0.0.1 API application that needs to return a simple PORO as json. I am using gem 'responders', '~> 2.3.0'
The object constructs correctly and works properly in the Rails server. It has only 4 attributes that are needed by the front-end.
The serializer is:
class WebsiteConfigSerializer < ActiveModel::Serializer
attributes :force_first_user_to_be_admin, :allows_delete_of_last_admin,
:is_private_website, :invite_only
end
The controller show method (the only method in the controller) is:
def show
config = WebsiteConfig.new
puts "Config: #{config.to_json}"
respond_to do |format|
format.json {render( json: config, status: 200 ) }
end
end
The log shows the request output, including the debugging puts statement:
Started GET "/config.json" for 127.0.0.1 at 2016-09-03 18:23:32 -0400
Processing by WebsiteConfigController#show as JSON
Config: {"force_first_user_to_be_admin":true, "allows_delete_of_last_admin":false, "is_private_website":true, "invite_only":true}
[active_model_serializers] Rendered WebsiteConfigSerializer with ActiveModelSerializers::Adapter::Attributes (0.13ms)
Completed 200 OK in 2ms (Views: 1.2ms | ActiveRecord: 0.0ms)
as expected.
The output of cURL is:
curl -sb -H "Accept:application/json" -H "Content-Type:application/json" http://localhost:3000/config
<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx</center>
</body>
</html>
This is NOT what I expected.
wget output is EMPTY (0 bytes). Also not what I expected.
Obviously I am missing something. Any help will be appreciated.
Your request has been redirected, check if you have some authentication code like requiring login or something else, then added them to the curl command

cURL post to server resulting in a UnknownFormat error

I am very new at rails and having a hard time doing a cURL post to my server. Any help would be apreciated.
I am posting JSON data to my server.
this is my curl post curl -X POST -H "Content-Type: application/json" -d '[{"photo":[{ "location": "location", "userID": "userid" },{ "location": "location", "userID": "userid" },{"location": "location", "userID": "userid"}]}]' http://localhost:3000/photo/create
this is my controller:
class SendphotoController < ApplicationController
def create
#photo = Photo.new(:photo => params[:location], :photo => params[:userID])
respond_to do |format|
if #photo.save
puts "Done"
else
puts "NOPE"
end
end
end
I get the error of ActionController::UnknownFormat (ActionController::UnknownFormat):
This is the full log:
Started POST "/photo/create" for 127.0.0.1 at 2013-09-08 22:03:56 -0400
Processing by SendphotoController#create as */*
Parameters: {"_json"=>[{"photo"=>[{"location"=>"location", "userID"=>"userid"}, {"location"=>"location", "userID"=>"userid"}, {"location"=>"location", "userID"=>"userid"}]}], "sendphoto"=>{"_json"=>[{"photo"=>[{"location"=>"location", "userID"=>"userid"}, {"location"=>"location", "userID"=>"userid"}, {"location"=>"location", "userID"=>"userid"}]}]}}
WARNING: Can't mass-assign protected attributes for Photo: photo
app/controllers/sendphoto_controller.rb:4:in `create'
(0.0ms) begin transaction
SQL (0.3ms) INSERT INTO "photos" ("created_at", "updated_at") VALUES (?, ?) [["created_at", Mon, 09 Sep 2013 02:03:56 UTC +00:00], ["updated_at", Mon, 09 Sep 2013 02:03:56 UTC +00:00]]
(215.8ms) commit transaction
Done
Completed 406 Not Acceptable in 235ms
ActionController::UnknownFormat (ActionController::UnknownFormat):
app/controllers/sendphoto_controller.rb:5:in `create'
You're using a respond_to block, but not any formats. Your block should look something like this:
respond_to do |format|
format.html {
# respond to a web form with HTML
}
format.json {
# respond to API request
}
end
If you just want a generic response for all formats, you can drop the respond_to bit altogether. But puts isn't going to work in a Controller context (or pretty much anywhere in Rails for that matter); you have to render something.
That might look something like this
def create
if Photo.create # ...
render text: "done"
else
render text: "nope"
end
end

in Ruby on Rails, updated gem causing mysql database rollback in formerly passing Capybara test

The following spec used to pass:
it "should allow me to register" do
fill_in "First name", with: "John"
fill_in "Last name", with: "Peters"
fill_in "Email", with: "user#example.com"
fill_in "Password", with: "foobar"
fill_in "Password confirmation", with: "foobar"
expect { click_button submit }.to change(User, :count).by(1)
end
With a test.log output of:
Started GET "/users/sign_up" for 127.0.0.1 at 2013-08-16 13:12:45 -0400
Processing by RegistrationsController#new as HTML
Rendered users/shared/_service.html.haml (1.9ms)
Rendered users/registrations/_newfields.haml (149.9ms)
Rendered users/shared/_links.haml (3.9ms)
Rendered users/registrations/new.html.haml within layouts/application (180.3ms)
Rendered shared/_header.haml (10.0ms)
Rendered shared/_footer.haml (12.4ms)
Completed 200 OK in 411ms (Views: 331.7ms | ActiveRecord: 30.0ms)
(120.9ms) SELECT COUNT(*) FROM `users`
Started POST "/users" for 127.0.0.1 at 2013-08-16 13:12:47 -0400
Processing by RegistrationsController#create as HTML
Parameters: {"utf8"=>"✓", "user"=>{"first_name"=>"John", "last_name"=>"Peters", "email"=>"user#example.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Sign up"}
(0.4ms) BEGIN
User Exists (0.4ms) SELECT 1 AS one FROM `users` WHERE `users`.`email` = BINARY 'user#example.com' LIMIT 1
SQL (1.5ms) INSERT INTO `users` (<values>) VALUES (NULL, NULL, NULL, NULL, 'USA', '2013-08-16 17:12:47', NULL, NULL, 'user#example.com', '$2a$10$E4/LZAvbf7HvFobBjFQxjOnHuO8cnBNJzMPQ3MMT9oVnou98DGqty', 'John', 1, '--- []\n', NULL, 'Peters', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, '2013-08-16 17:12:47', NULL)
(30.4ms) COMMIT
(0.1ms) BEGIN
(0.5ms) UPDATE `users` SET `last_sign_in_at` = '2013-08-16 17:12:47', `current_sign_in_at` = '2013-08-16 17:12:47', `last_sign_in_ip` = '127.0.0.1', `current_sign_in_ip` = '127.0.0.1', `sign_in_count` = 1, `updated_at` = '2013-08-16 17:12:47', `interest_areas` = '--- []\n' WHERE `users`.`id` = 1
(0.5ms) COMMIT
Redirected to http://www.example.com/
Completed 302 Found in 210ms (ActiveRecord: 0.0ms)
Started GET "/" for 127.0.0.1 at 2013-08-16 13:12:47 -0400
However, after running bundle update, the test now fails with the error:
Failure/Error: expect { click_button submit }.to change(User, :count).by(1)
count should have been changed by 1, but was changed by 0
And test.log output of:
Started GET "/users/sign_up" for 127.0.0.1 at 2013-08-16 13:09:19 -0400
Processing by RegistrationsController#new as HTML
Rendered users/shared/_service.html.haml (2.0ms)
Rendered users/registrations/_newfields.haml (183.5ms)
Rendered users/shared/_links.haml (5.8ms)
Rendered users/registrations/new.html.haml within layouts/application (220.0ms)
Rendered shared/_header.haml (10.2ms)
Rendered shared/_footer.haml (10.7ms)
Completed 200 OK in 623ms (Views: 522.2ms | ActiveRecord: 57.1ms)
(17.3ms) SELECT COUNT(*) FROM `users`
Started POST "/users" for 127.0.0.1 at 2013-08-16 13:09:20 -0400
Processing by RegistrationsController#create as HTML
Parameters: {"utf8"=>"✓", "user"=>{"first_name"=>"John", "last_name"=>"Peters", "email"=>"user#example.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Sign up"}
(0.2ms) BEGIN
(0.1ms) ROLLBACK
Redirected to http://www.example.com/users/sign_up
Completed 302 Found in 11ms (ActiveRecord: 0.3ms)
Started GET "/users/sign_up" for 127.0.0.1 at 2013-08-16 13:09:20 -0400
The divergence occurs after the BEGIN line in the database queries; the new version does a ROLLBACK immediately after.
Only the gems have changed between the passing case and the failing case. The diff between the two commits (mainly a difference between their Gemfile.lock files) can be found here: http://pastie.org/private/d4a49zoegu0j3faigfjfw
Does anyone know whether updating any of those gems could have caused this error?
Edit - Here is the Registration Controller's #create code:
def create
build_resource
if resource.save
if resource.active_for_authentication?
set_flash_message :notice, :signed_up if is_navigational_format?
sign_up(resource_name, resource)
respond_with resource, :location => after_sign_up_path_for(resource)
else
set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_navigational_format?
expire_session_data_after_sign_in!
respond_with resource, :location => after_inactive_sign_up_path_for(resource)
end
else
clean_up_passwords resource
## logic of path
redirect_to new_user_registration_path, alert: resource.errors.full_messages.join('<br />')
end
end
Based solely on general experience and not on specific knowledge of those gem version changes, I can say with some confidence that updating that many gems, including at least two gems with a major version change (i.e. delayed_job*), could have caused this error. :-) I know that's not much help, but if you post the related code (e.g. your RegistrationsController), I bet the community can help you find the issue fairly quickly and perhaps help others in the future.
I simply reverted to my old Gemfile.lock, emptied my gem set, and installed them all again (effectively reverting them to their old versions).

Unable to pass params data to create a user

I have a rails app that accepts json request to create a user. A sign_up basically which is a GET. I can't create a user when i pass in this url http://localhost:3000/sign_up.json?username=chalam&email=holy#yahoo.com&name=chalami&password=chalami
I know I am passing the password in the open but that is not my concern here. i checked the logs and this is what i see
Started GET "/sign_up.json?username=chalam&email=holy#yahoo.com&name=chalami&password=[FILTERED]" for 127.0.0.1 at 2013-05-28 10:37:37 +0700
Processing by UsersController#create as JSON
Parameters: {"username"=>"chalam", "email"=>"holy#yahoo.com", "name"=>"chalami", "password"=>"[FILTERED]"}
(0.1ms) begin transaction
User Exists (0.1ms) SELECT 1 AS one FROM "users" WHERE "users"."username" IS NULL LIMIT 1
User Exists (0.0ms) SELECT 1 AS one FROM "users" WHERE "users"."email" IS NULL LIMIT 1
(0.0ms) rollback transaction
(0.0ms) begin transaction
CACHE (0.0ms) SELECT 1 AS one FROM "users" WHERE "users"."username" IS NULL LIMIT 1
CACHE (0.0ms) SELECT 1 AS one FROM "users" WHERE "users"."email" IS NULL LIMIT 1
(0.0ms) rollback transaction
Completed 200 OK in 6ms (Views: 0.1ms | ActiveRecord: 0.3ms)
As you can see although the parameter Parameters: {"username"=>"chalam", "email"=>"holy#yahoo.com", "name"=>"chalami", "password"=>"[FILTERED]"} clearly show that parameters are being passed, they are not being entered into the database CACHE (0.0ms) SELECT 1 AS one FROM "users" WHERE "users"."username" IS NULL LIMIT 1
CACHE (0.0ms) SELECT 1 AS one FROM "users" WHERE "users"."email" IS NULL LIMIT 1
Main problem is data from the params is not being "used" to create a User
One thing to note is I can create a user through the console in terminal. I will try to include all relevant information
rails version: 3.2.13 and
I am using thin instead of WEBBRICK
My user.rb
class User < ActiveRecord::Base
attr_accessible :email, :name, :username
attr_accessor :password
before_save :encrypt_password
validates_uniqueness_of :username, :email
validates_presence_of :password, :on => :create
validates_presence_of :email, :username
def encrypt_password
if password.present?
self.password_salt = BCrypt::Engine.generate_salt
self.password_hash = BCrypt::Engine.hash_secret(password, password_salt)
end
end
def self.authenticate(username, password)
user = find_by_username(username)
if(user && user.password_hash == BCrypt::Engine.hash_secret(password, user.password_salt))
user
else
nil
end
end
end
My Controller
class UsersController < ApplicationController
respond_to :json
def new
#user = User.new
end
def create
#user = User.new(params[:user])
#user.save
if #user.save
respond_to do |format|
format.json { render :json => {:status => "200", :message => "Signed up successfully"}}
end
else
respond_to do |format|
puts #user.errors.inspect
format.json { render :json => {:status => "400", :message => "Failed"}}
end
end
end
def index
#user = User.all
render :json =>#user
end
end
Okay, so I have come up with a solution and I thought I should post it, it might help people
Problem: I could not create a user using a Json response although I could do it through rails console
Mistakes:
I created a GET route to create a User which compromises security
I added the password field to attr_accessor and not to attr_accessible
Solutions:
changed the action from GET to POST(in the routes.rb). To create a user(for a POST) I used curl. In my case my curl statement was
curl -v -H "Accept: application/json" -H "Content-type: application/json" -X POST -d ' {"user":{"name":"name","username":"username","email":"email#email.com","password":"app123"}}' http://localhost:3000/sign_up. Here is a useful post about curl
2.In my user model I included attr_accessor :password as well as attr_accessible :password