I am trying to fix the following rails functional test:
test "should create broadcast" do
login_as(:one_details)
assert_difference('Broadcast.count') do
post :create, feeds: [:twitter, {alumni_email: 'test#email.com'}], broadcast: {id: 2, content: #broadcast.content, user: #user_details.user_id}
end
assert_redirected_to "#{broadcast_path}?page=1"
end
Here is the error:
1) Error:
BroadcastsControllerTest#test_should_create_broadcast:
ActionController::UrlGenerationError: No route matches {:action=>"show", :controller=>"broadcasts"} missing required keys: [:id]
test/controllers/broadcasts_controller_test.rb:35:in `block in <class:BroadcastsControllerTest>'
I have this in the routes file:
resources :broadcasts, except: [:edit, :update]
In the broadcasts_controller the show method looks like this:
def show
if is_admin?
respond_to do |format|
format.js { render partial: 'show_local',
locals: {broadcast: #broadcast, current_page: #current_page},
layout: false }
format.html # show.html.erb
format.json # show.json.builder
end
else
indicate_illegal_request I18n.t('not allowed to view this')
end
end
The broadcast controller create method:
def create
#broadcast = Broadcast.new(broadcast_params)
# Wire up broadcast with the current user (an administrator)
# Will be an admin user (see before_filter)
# Note the current_user is a user_detail object so we need
# to navigate to its user object
#broadcast.user = current_user.user
# Doing the next line forces a save automatically. I want to defer this
# until the "if" statement
#current_user.user.broadcasts << #broadcast
no_errors = false
respond_to do |format|
if #broadcast.save
# Only after saving do we try and do the real broadcast. Could have been
# done using an observer, but I wanted this to be more explicit
results = BroadcastService.broadcast(#broadcast, params[:feeds])
if results.length > 0
# Something went wrong when trying to broadcast to one or more of the
# feeds.
#broadcast.errors[:base] << ("#{I18n.t('broadcasts.unable-message')}: #{results.inspect}")
flash[:error] = I18n.t('broadcasts.saved-but-message')
else
flash[:notice] = I18n.t('broadcasts.saved-message')
no_errors = true
end
if no_errors
format.html { redirect_to(broadcasts_url(page: #current_page)) }
format.json { render json: #broadcast, status: :created, location: #broadcast }
else
format.html { render :new }
format.xml {
# Either say it partly worked but send back the errors or else send
# back complete failure indicator (couldn't even save)
if results
render json: #broadcast.errors, status: :created, location: #broadcast
else
render json: #broadcast.errors, status: :unprocessable_entity
end
}
end
end
end
end
Change
assert_redirected_to "#{broadcast_path}?page=1"
to
assert_redirected_to "#{broadcasts_path}?page=1"
also change
post :create, feeds: [:twitter, {alumni_email: 'test#email.com'}], broadcast: {id: 2, content: #broadcast.content, user: #user_details.user_id}
to
post :create, feeds: [:twitter, {alumni_email: 'test#email.com'}], broadcast_params: {id: 2, content: #broadcast.content, user: #user_details.user_id}
you are not passing an id in the redirect check so you either make it broadcasts_path
Related
I want to grab content from a website, that I input into a submit form, and store that info as a json I can save to my db. I am trying to use HTTParty, but I'm not quite sure how to implement it to grab the data. Here is what I have so far.
controller
class UrlsController < ApplicationController
before_action :set_url, only: [:show, :edit, :update, :destroy]
#require "addressable/uri"
#Addressable::URI.parse(url)
# GET /urls
# GET /urls.json
def index
#urls = Url.all
end
# GET /urls/1
# GET /urls/1.json
def show
end
# GET /urls/new
def new
#url = Url.new
end
# GET /urls/1/edit
def edit
end
def uri?(string)
uri = URI.parse(string)
%w( http https ).include?(uri.scheme)
rescue URI::BadURIError
false
rescue URI::InvalidURIError
false
end
# POST /urls
# POST /urls.json
def create
#url = Url.new(url_params)
#app_url = params[:url]
respond_to do |format|
if #url.save
format.html { redirect_to #url, notice: 'Url was successfully created.' }
format.json { render action: 'show', status: :created, location: #url }
wordcount
else
format.html { render action: 'new' }
format.json { render json: #url.errors, status: :unprocessable_entity }
end
end
end
def wordcount
# Choose the URL to visit
#app_url = #url
#words = HTTParty.get(#app_url)
# Trick to pretty print headers
#wordcount = Hash[*#words]
end
# PATCH/PUT /urls/1
# PATCH/PUT /urls/1.json
def update
respond_to do |format|
if #url.update(url_params)
format.html { redirect_to #url, notice: 'Url was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #url.errors, status: :unprocessable_entity }
end
end
end
# DELETE /urls/1
# DELETE /urls/1.json
def destroy
#url.destroy
respond_to do |format|
format.html { redirect_to urls_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_url
#url = Url.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def url_params
params.require(:url).permit(:url)
end
end
That is my controller.rb. I am getting a 'bad argument (expected URI object or URI string)' from the line #words = HTTParty.get(#app_url) I need to change what url is put into the form to a valid URL, grab the content I want from that URL, and save that information.
Try something like this:
response = HTTParty.get('https://google.com')
puts response.body, response.code, response.message, response.headers.inspect
To answer your question you can implement the following method, make a new class or put it in a helper.
Might need to include HTTParty
def url_getter(url)
HTTParty.get(url)
end
and call it:
url_getter(#app_url)
I want show a daycare details on show page but I got this error
NoMethodError : undefined method `find' for nil:NilClass
from daycare controller file and i'm not get any idea. I have mentioned below that error line.
This is my Controller file
class DayCaresController < ApplicationController
before_filter :authenticate_user!
before_action :set_day_care, only: [:show, :edit, :update, :destroy]
# GET /day_cares
# GET /day_cares.json
def index
#day_cares = DayCare.all
end
# GET /day_cares/1
# GET /day_cares/1.json
def show
end
# GET /day_cares/new
def new
#day_care = DayCare.new
end
# GET /day_cares/1/edit
def edit
end
# POST /day_cares
# POST /day_cares.json
def create
#day_care = current_user.build_day_care(day_care_params)
respond_to do |format|
if #day_care.save
UserMailer.welcome_email(#user).deliver
format.html { redirect_to #day_care, :gflash => { :success => 'Day care was successfully created.'} }
format.json { render :show, status: :created, location: #day_care }
else
format.html { render :new }
format.json { render json: #day_care.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /day_cares/1
# PATCH/PUT /day_cares/1.json
def update
respond_to do |format|
if #day_care.update(day_care_params)
format.html { redirect_to #day_care, :gflash => { :success => 'Day care was successfully updated.'} }
format.json { render :show, status: :ok, location: #day_care }
else
format.html { render :edit }
format.json { render json: #day_care.errors, status: :unprocessable_entity }
end
end
end
# DELETE /day_cares/1
# DELETE /day_cares/1.json
def destroy
#day_care.destroy
respond_to do |format|
format.html { redirect_to day_cares_url, :gflash => { :success => 'Day care was successfully destroyed.'} }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions
def set_day_care
#day_care = current_user.day_care.find(params[:id]) # => **I got error this line**
end
# Never trust parameters from the scary internet, only allow the white list through.
def day_care_params
params.require(:day_care).permit(:name, :address, :office_phone, :cell_phone, :logo, :website, :user_id)
end
def dashboard
end
def profile
end
end
If user has_many: day_cares then use this name instead of day_care:
#day_care = current_user.day_cares.where(id: params[:id]).take
or probably as you wrote:
#day_care = current_user.day_cares.find(params[:id])
But with arrays instead of single instance (day_cares).
Also you can use just:
#day_care = DayCare.find(params[:id])
If you search by id. Or if you need to check that it's users day_care:
#day_care = DayCare.where(id: params[:id], user: current_user).take
current_user.day_care.find is not available, because you can only perform queries on plural associations. So given that the model associations are setup correctly as:
class User < ActiveRecord:Base
has_many :day_cares
...
end
the solution is probably just to resolve the spelling error from
`current_user.day_care.find` #wrong!
to
`current_user.day_cares.find` #right!
I want to be able to simply determine if a user credentials are correctly supplied in an iOS app I'm creating.
The way I have it setup now is with a sessions_controller.rb that handles and returns a user token. The problem is if I want to still log on through the web (not just a check via curl or similar), it doesn't authenticate and spits out
{"success":false,"message":"Error with your login or password"}
So my question is...how can I do authentication and still keep my web-login operational? Here are my related files. My hope was I could curl to a url such as localhost:3000/auth_checks and get one type of authentication response, and continue to have my users login through localhost:3000/sign_in.
From devise.rb
config.skip_session_storage = [:http_auth, :token_auth]
config.token_authentication_key = :auth_token
From routes.rb
resources :clippings
root to: 'clippings#index'
#devise_for :users
resources :auth_checks
devise_for(:users, :controllers => { :sessions => "sessions" })
resources :posts do
end
From auth_checks_controller.rb
class AuthChecksController < ApplicationController
before_filter :authenticate_user!
# GET /auth_checks
# GET /auth_checks.json
def index
#auth_checks = AuthCheck.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #auth_checks }
end
end
# GET /auth_checks/1
# GET /auth_checks/1.json
def show
#auth_check = AuthCheck.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #auth_check }
end
end
# GET /auth_checks/new
# GET /auth_checks/new.json
def new
#auth_check = AuthCheck.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #auth_check }
end
end
# GET /auth_checks/1/edit
def edit
#auth_check = AuthCheck.find(params[:id])
end
# POST /auth_checks
# POST /auth_checks.json
def create
#auth_check = AuthCheck.new(params[:auth_check])
respond_to do |format|
if #auth_check.save
format.html { redirect_to #auth_check, notice: 'Auth check was successfully created.' }
format.json { render json: #auth_check, status: :created, location: #auth_check }
else
format.html { render action: "new" }
format.json { render json: #auth_check.errors, status: :unprocessable_entity }
end
end
end
# PUT /auth_checks/1
# PUT /auth_checks/1.json
def update
#auth_check = AuthCheck.find(params[:id])
respond_to do |format|
if #auth_check.update_attributes(params[:auth_check])
format.html { redirect_to #auth_check, notice: 'Auth check was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #auth_check.errors, status: :unprocessable_entity }
end
end
end
# DELETE /auth_checks/1
# DELETE /auth_checks/1.json
def destroy
#auth_check = AuthCheck.find(params[:id])
#auth_check.destroy
respond_to do |format|
format.html { redirect_to auth_checks_url }
format.json { head :no_content }
end
end
end
Learned a lot...here's what I ended up doing. If you're in this position, I highly recommend putting in the time (not very much) to do this method. http://www.cocoahunter.com/blog/2013/02/13/restful-api-authentication/
If you're like me, you already have a userbase using the standard devise login structure.
I added this to my routes.rb
namespace :api do
namespace :v1 do
resources :tokens,:only => [:create, :destroy]
end
end
Then created and added tokens_controller.rb inside of controllers/api/v1/ (which I created)
# encoding: utf-8
class Api::V1::TokensController < ApplicationController
skip_before_filter :verify_authenticity_token
respond_to :json
def create
email = params[:email]
password = params[:password]
if request.format != :json
render :status=>406, :json=>{:message=>"The request must be json"}
return
end
if email.nil? or password.nil?
render :status=>400,
:json=>{:message=>"The request must contain the user email and password."}
return
end
#user=User.find_by_email(email.downcase)
if #user.nil?
logger.info("User #{email} failed signin, user cannot be found.")
render :status=>401, :json=>{:message=>"Invalid email or passoword."}
return
end
# http://rdoc.info/github/plataformatec/devise/master/Devise/Models/TokenAuthenticatable
#user.ensure_authentication_token!
if not #user.valid_password?(password)
logger.info("User #{email} failed signin, password \"#{password}\" is invalid")
render :status=>401, :json=>{:message=>"Invalid email or password."}
else
render :status=>200, :json=>{:token=>#user.authentication_token}
end
end
def destroy
#user=User.find_by_authentication_token(params[:id])
if #user.nil?
#logger.info(“Token wasnot found.”)
#render :status=>404, :json=>{:message=>”Invalid token.”}
else
#user.reset_authentication_token!
render :status=>200, :json=>{:token=>params[:id]}
end
end
end
That's literally all I had to do. I can now test to this api for authentication from my iOS app. Hope that makes sense to someone out there!
My Rails app has a player class that works perfectly. Players can be created, deleted, and updated from my rails control panel without any issues.
I would like a remote counterpart to be able to join in the fun by creating players using a JSON request. Following the advice of the auto generated Rails comments above my create method : # POST /players.json I have started sending requests to localhost:3000/players.json
The JSON
{
"player": {
"name": "test",
"room_id": 0,
"skin_id": 1,
"head_id": 2,
"torso_id": 3,
"legs_id": 4,
"x_position": 5,
"y_position": 6,
"direction": 7,
"action": "",
"gender": "f"
}
}
However, I am running into this error message:
ActionController::ParameterMissing in PlayersController#create
param not found: player
So I guess my question is: How should I structure the JSON I am sending?
Additional info:
Ruby Version: 2.0
Rails Version: 4.0
I have tried sending my requests using Postman
Update - Player Params
Here is the player params method from my controller (as requested):
def player_params
params.require(:player).permit(:name, :room_id, :skin_id, :head_id, :torso_id, :legs_id, :x_position, :y_position, :direction, :action, :gender)
end
Update 2 - Player controller
class PlayersController < ApplicationController
before_action :set_player, only: [:show, :edit, :update, :destroy]
skip_before_filter :verify_authenticity_token, :if => Proc.new { |c| c.request.format == 'application/json' }
# GET /players
# GET /players.json
def index
#players = Player.all
end
# GET /players/1
# GET /players/1.json
def show
end
# GET /players/new
def new
#player = Player.new
end
# GET /players/1/edit
def edit
#rooms = Room.all.map { |room| [room.name, room.id] }
end
# POST /players
# POST /players.json
def create
#player = Player.new(player_params)
respond_to do |format|
if #player.save
format.html { redirect_to #player, notice: 'Player was successfully created.' }
format.json { render action: 'show', status: :created, location: #player }
else
format.html { render action: 'new' }
format.json { render json: #player.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /players/1
# PATCH/PUT /players/1.json
def update
respond_to do |format|
if #player.update(player_params)
format.html { redirect_to #player, notice: 'Player was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #player.errors, status: :unprocessable_entity }
end
end
end
# DELETE /players/1
# DELETE /players/1.json
def destroy
#player.destroy
respond_to do |format|
format.html { redirect_to players_url }
format.json { head :no_content }
end
end
def manage_furni
#player = Player.find(params[:id])
#furni = Furni.all
end
def add_furni
player = Player.find(params[:id])
player.furnis << Furni.find(params[:furni])
redirect_to manage_furni_path(player)
end
def remove_furni
player = Player.find(params[:id])
item = InventoryItem.find(params[:item])
player.inventory_items.delete(item)
redirect_to manage_furni_path(player)
end
private
# Use callbacks to share common setup or constraints between actions.
def set_player
#player = Player.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def player_params
params.require(:player).permit(:name, :room_id, :skin_id, :head_id, :torso_id, :legs_id, :x_position, :y_position, :direction, :action, :gender)
end
end
Update 3: logs
(
"Processing by PlayersController#create as JSON",
"Completed 400 Bad Request in 31ms",
"ActionController::ParameterMissing (param not found: player):",
"app/controllers/players_controller.rb:103:in `player_params'",
"app/controllers/players_controller.rb:40:in `create'",
"Rendered /Users/drewwyatt/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-4.0.0/lib/action_dispatch/middleware/templates/rescues/_source.erb (0.5ms)",
"Rendered /Users/drewwyatt/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-4.0.0/lib/action_dispatch/middleware/templates/rescues/_trace.erb (0.9ms)",
"Rendered /Users/drewwyatt/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-4.0.0/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (0.8ms)",
"Rendered /Users/drewwyatt/.rvm/gems/ruby-2.0.0-p247/gems/actionpack-4.0.0/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (16.3ms)"
){
}
First of all, I think your data format is ok and is not the problem here. When I ran exactly into the same problem it was because I did not send the Content-Type: application/json header along with my request.
In Postman, you can select the 'raw' data format and then 'JSON (application/json)' to include this header. In my case it looks like this:
Alternatively, you can also try it with curl (source):
curl -X POST -H "Content-Type: application/json" -d '{"player": {"name": "test","room_id": 0,"skin_id": 1,"head_id": 2,"torso_id": 3,"legs_id": 4,"x_position": 5,"y_position": 6,"direction": 7,"action": "","gender": "f"}}' localhost:3000/players.json
If you omit the -H "Content-Type: application/json", then you will receive a 400 response with the "param not found" error, if you include it it should work.
If you are trying this:
via Postman - Under form-data tab, you need to have the vars as :
player[name]
player[room_id]
.
.
via jQuery:
$.ajax({ url: 'url', type: 'post', data: { player: { name: 'Test', room_id: '0' } } })
I have a nested route:
resources :stories do
resources :comments
end
this is my create method in controller:
def create
#story = Story.find(params[:story_id])
#comment = #story.comments.build(params[:comment])
#comments = #story.comments.all
respond_to do |format|
if #comment.save
format.html { redirect_to #story, notice: t('controllers.comments.create.flash.success') }
format.json { render json: #comment, status: :created, location: #comment }
else
format.html { render template: "stories/show" }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
And here is it's test:
setup do
#comment = comments(:one)
#story = stories(:one)
end
....
test "should create comment" do
assert_difference('Comment.count') do
post :create, :story_id => #story.id, comment: { content: #comment.content, name: #comment.name, email: #comment.email }
end
assert_redirected_to #story_path
end
that ends up with this error:
1) Failure:
test_should_create_comment(CommentsControllerTest) [/home/arach/workspace/Web/ruby/nerdnews/test/functional/comments_controller_test.rb:25]:
Expected response to be a redirect to <http://test.host/stories/980190962/comments> but was a redirect to <http://test.host/stories/980190962>
I don't know why the test expect to redirect to stories/:id/comments. I tried other things like story_comment_path but it didn't help either. story_path without # also ends up with another error:
ActionController::RoutingError: No route matches {:action=>"show", :controller=>"stories"}
same error happens for story_path, :story_id => #story.id. Any idea why this happens?
I think it should be story_path(#story.id). See here.