i tried to use the following tutorial for rails api authentication by using json & ajax: http://jessehowarth.com/devise
it seem to work, but no matter what login-credentials i enter (existing and non-existing), it fails everytime i hit submit.
i make the request using node.js
var post_data = querystring.stringify({
'email' : 'foo#bar.com',
'password': 'foo',
'remember_me': 1
});
var options = {
host: 'localhost',
path: '/users/sign_in.json',
port: '3000',
method: 'POST'
};
callback = function(response) {
var str = '';
response.on('data', function (chunk) {
str += chunk;
});
response.on('end', function () {
console.log(str);
});
}
var req = http.request(options, callback);
req.write(post_data);
req.end();
my devise-session controller looks like this:
class SessionsController < Devise::SessionsController
def create
respond_to do |format|
format.html{ super }
format.json do
resource = warden.authenticate!(:scope => resource_name, :recall => "#{controller_path}#failure")
return sign_in_and_redirect(resource_name, resource)
end
end
end
def sign_in_and_redirect(resource_or_scope, resource=nil)
scope = Devise::Mapping.find_scope!(resource_or_scope)
resource ||= resource_or_scope
sign_in(scope, resource) unless warden.user(scope) == resource
respond_to do |format|
format.json {render :json => {:success => true, :redirect => stored_location_for(scope) || after_sign_in_path_for(resource)}}
format.html {redirect_to root_url}
end
end
def failure
respond_to do |format|
format.json { render:json => {:success => false, :errors => ["Login failed."]} }
end
end
end
the output i get:
{"success":false,"errors":["Login failed."]}
any advice on this?
thanks!
Okay, actually it was my fault. but if someone is as silly as me:
I used the parameters email, password and remember_me instead of user[email], user[password] and user[remember_me]…
Solved!
Related
I have an API based Rails app and I need to add a changing password section for clients after login. this is y codes so far:
# routes.rb
resources :passwords, only: %i[index]
post '/passwords/update_password', to: 'passwords#update_password'
passwords_controller.rb
class Api::PasswordsController < ApplicationController
respond_to :json
before_action :auth_check
def auth_check
if !user_signed_in?
render json: {:status => false, :msg => 'Access denied!'}
end
end
def update_password
user = User.find(current_user['_id'])
password = params["password"]
if password && !password.blank?
user.password = user.password_confirmation = password
end
if user.save
render json: {company: user}, status: 200
else
render json: {message: "Problem updating company"}, status: 500
end
end
end
And this is XHR request from client-side
axios({
url: '/api/passwords/update_password',
method: 'POST',
body: {
password: password,
password_confirmation: password_confirmation
}
})
.then(response => {
console.log(response);
})
.catch(err => {
console.log(err);
});
Its not working!
You should be able to use current_user. I edited the code. If it doesn't work, can you write the error here? Make sure the post request goes to update_password action.
class Api::PasswordsController < ApplicationController
respond_to :json
before_action :auth_check
def update_password
password = params.dig(:password)
password_confirmation = params.dig(:password_confirmation)
if password.present? && password == password_confirmation
if current_user.update(password: password, pasword_confirmation: password_confirmation)
render json: { company: user }, status: 200
else
render json: { message: 'Problem updating company' }, status: 500
end
end
end
private
def auth_check
render json: { status: false, msg: 'Access denied!' } unless user_signed_in?
end
end
I have js file:
$('#some_btn').click(function() {
var valuesToSubmit = $('#some_form').serialize();
var url = $('#some_form').attr('action');
console.log("VALUE: " + valuesToSubmit);
console.log("URL: " + search_url);
$.ajax({
type: 'POST',
url: url, //sumbits it to the given url of the form
data: valuesToSubmit,
dataType: "JSON",
success: function(data) {
console.log("saved");
console.log(data);
}
});
return false;
});
Controller action which responses:
def some_action()
...
#response = {resp: "ack"}
respond_with #response do |format|
format.json { render :layout => false, :text => #response }
end
end
Route:
post '/abc/some_action', to: 'abc#some_action'
But after executing it I receive:
ArgumentError
Nil location provided. Can't build URI.
#response = {resp: "ack"}
respond_with #response do |format| # <--- Error here
format.json { render :layout => false, :text => #response }
end
respond_with expects an AR object from which a route could be deduced.
Change with:
#response = {resp: "ack"}
respond_to do |format|
format.json { render json: #response }
format.js { render json: #response }
end
an alternative is to force the controller to render only json for a particular action. Weird because it means you were unable to send the proper request.
But in this case:
respond_to :json, :only => :some_action
In your action:
render json: #response
In your controller add this line
class YourController < ...
respond_to :json
and then
#response = {resp: "ack"}
respond_with(#response)
I want to get data from client side,and display in my ror website using post method in create method,how to write the function for fetching data from client side(android) to ror.
def create
#post = Post.new(params[:post])
data_json = JSON.parse request.body.read
#respond_to do |format|
if #post.save
flash[:notice] = "Prayer Successfully created."
#posts = Post.paginate(page: params[:page],:per_page => 5)
#post = Post.new(data_json)
#post.save
#format.json{ render :json => #post, :status => :created }
else
flash[:notice] = "Error"
#posts = Post.paginate(page: params[:page],:per_page => 5)
#format.json{ render :json => #post, :status => :created }
end
end
There is not enough data in your question but ill try to help you.
Your client-side logic should look like that (jQuery code):
$("#some_button").bind("click", function(event){
$.ajax({
type: "POST",
url: "/bla-bla/create",
data: { my_param: JSON.stringify(my_data) }
});
});
And action of controller that match to route /bla-bla/create:
def create
my_var = JSON.parse(params[:my_param])
...
#do what you want with "my_var"
Hope it'll help you!
The following attempt_login method is called using Ajax after a login form is submitted.
class AccessController < ApplicationController
[...]
def attempt_login
authorized_user = User.authenticate(params[:username], params[:password])
if authorized_user
session[:user_id] = authorized_user.id
session[:username] = authorized_user.username
flash[:notice] = "Hello #{authorized_user.name}."
redirect_to(:controller => 'jobs', :action => 'index')
else
[...]
end
end
end
The problem is that redirect_to doesn't work.
How would you solve this ?
Finally, I just replaced
redirect_to(:controller => 'jobs', :action => 'index')
with this:
render :js => "window.location = '/jobs/index'"
and it works fine!
There is very easy way to keep the flash for the next request. In your controller do something like
flash[:notice] = 'Your work was awesome! A unicorn is born!'
flash.keep(:notice)
render js: "window.location = '#{root_path}'"
The flash.keep will make sure the flash is kept for the next request.
So when the root_path is rendered, it will show the given flash message. Rails is awesome :)
I think this is slightly nicer:
render js: "window.location.pathname='#{jobs_path}'"
In one of my apps, i use JSON to carry on the redirect and flash message data. It would look something like this:
class AccessController < ApplicationController
...
def attempt_login
...
if authorized_user
if request.xhr?
render :json => {
:location => url_for(:controller => 'jobs', :action => 'index'),
:flash => {:notice => "Hello #{authorized_user.name}."}
}
else
redirect_to(:controller => 'jobs', :action => 'index')
end
else
# Render login screen with 422 error code
render :login, :status => :unprocessable_entity
end
end
end
And simple jQuery example would be:
$.ajax({
...
type: 'json',
success: functon(data) {
data = $.parseJSON(data);
if (data.location) {
window.location.href = data.location;
}
if (data.flash && data.flash.notice) {
// Maybe display flash message, etc.
}
},
error: function() {
// If login fails, sending 422 error code sends you here.
}
})
Combining the best of all answers:
...
if request.xhr?
flash[:notice] = "Hello #{authorized_user.name}."
flash.keep(:notice) # Keep flash notice around for the redirect.
render :js => "window.location = #{jobs_path.to_json}"
else
...
def redirect_to(options = {}, response_status = {})
super(options, response_status)
if request.xhr?
# empty to prevent render duplication exception
self.status = nil
self.response_body = nil
path = location
self.location = nil
render :js => "window.location = #{path.to_json}"
end
end
I didn't want to modify my controller actions so I came up with this hack:
class ApplicationController < ActionController::Base
def redirect_to options = {}, response_status = {}
super
if request.xhr?
self.status = 200
self.response_body = "<html><body><script>window.location.replace('#{location}')</script></body></html>"
end
end
end
I have the following function in controller
def by_xy
#obj = BldPoly::find_by_xy(:x => params['x'], :y => params['y'])
respond_to do |format|
format.html { render :layout => false }
format.xml { render :layout => false }
format.json { render :layout => false }
end
and planning to write the automatic test in the following way
xml = nil
get :by_xy, {:x => 4831, :y => 3242, :format => :json}
assert_nothing_thrown { xml = REXML::Document.new(#response.body) }
td = REXML::XPath.first(xml, "//result/item")
assert_equal need_value, td.value
and I get
Completed in 50ms (View: 0, DB: 230) | 406 Not Acceptable [http://test.host/search/by_xy/4831/3242.json]
when I missed format in testing code - all works correctly,
how should I write the test?
I figured this out, actually; this is how it should be
get :by_xy, {:x => i[:x], :y => i[:y]}, :format => :json
For rails 5.1, when doing a post, I had to include the format attribute inside of my params hash
share_params = {
email: nil,
message: 'Default message.'
format: :json
}
post image_share_path(#image), params: share_params
assert_response :unprocessable_entity
If not I would get the error ActionController::UnknownFormat inside of my create controller
def create
#image = Image.new(image_params)
if #image.save
flash[:success] = 'Your image was saved successfully.'
redirect_to #image
else
respond_to do |format|
format.json do
render json: { #image.to_json },
status: :unprocessable_entity
end
end
end