Upload image with RSpec has unexpected class on controller - ruby

I'm in trouble with RSpec and fixture_file_upload on post request.
Here's the problem: I'm trying to send an image by upload to create a category with image, but when the image arrives, it changes it's class type.
I'm waiting to get in params[:category][:image] an ActionDispatch::Http::UploadedFile but what I receive is ActionController::Parameters.
My request example:
context 'when creates a new main category with valid params' do
let(:category) do
{ category: { name: 'Bolos E bolos',
description: 'São bolos sim',
locale: 'pt-BR',
image: fixture_file_upload('images/test-image.png', 'image/png') } }
end
post '/v4/categories' do
it 'upload image' do
expect { do_request(category) }.to change { ActiveStorage::Blob.count }.from(0).to(1)
end
end
end
what I got:
Failure/Error: expect { do_request(category) }.to change { ActiveStorage::Blob.count }.by(1)
expected `ActiveStorage::Blob.count` to have changed by 1, but was changed by 0
How do I send the image as upload and get it on the controller as ActionDispatch::Http::UploadedFile instead ActionController::Parameters

I could not get your controller spec working, but I managed to get an equivalent request spec working. Having spent 45+ minutes getting no where, I think this is the best I can do. This seems to work. (Just make sure you have an avatar.jpg in the public folder of your rails app.)
## spec/requests/user_spec.rb
require 'rails_helper'
RSpec.describe "Users", type: :request do
describe "it attaches uploaded files" do
it 'attaches the uploaded file' do
file = fixture_file_upload(Rails.root.join('public', 'avatar.jpg'), 'image/jpg')
expect {
post api_users_path, params: { user: {username: "Ben", avatar: file } }
}.to change(ActiveStorage::Attachment, :count).by(1)
end
end
end

Related

Ruby Hash Alignment

I'm trying to correct a linter error in my requests test file. I have a context block as follows:
context 'when the request is valid' do
before(:each) do
post '/api/v1/budgets',headers: authenticated_header(#user), params: {
budget: valid_attributes
}
end
end
However, I keep getting the following error:
C: Layout/ArgumentAlignment: Align the arguments of a method call if they span more than one line.
What is the proper way to align this block?
When looking at the RuboCop Layout/ArgumentAlignment documentation my guess would be:
context 'when the request is valid' do
before(:each) do
post '/api/v1/budgets',
headers: authenticated_header(#user),
params: { budget: valid_attributes }
end
end
When you need multi-line params it should probably look like this:
context 'when the request is valid' do
before(:each) do
post '/api/v1/budgets',
headers: authenticated_header(#user),
params: {
budget: valid_attributes
}
end
end
If you have more than one argument on the first line:
context 'when the request is valid' do
before(:each) do
post '/api/v1/budgets', headers: authenticated_header(#user), params: {
budget: valid_attributes
}
end
end
When you have a long method name you could also consider moving the first argument to the next line to reduce intention for all other arguments:
context 'when the request is valid' do
before(:each) do
a_somewhat_long_method_name
'/api/v1/budgets',
headers: authenticated_header(#user),
params: { budget: valid_attributes }
end
end
The above amuses you use the default configuration (:with_first_argument).

Set http status code 201 to an API response in action controller rails

I'm new to rails and I'm building a Rails app that will function as an API. Currently I don't have any models or database just an Api::ProductController controller:
class Api::ProductController < ApplicationController
def create
Rails.logger.info "product was created and the parameters are #{product_params[:name]}, #{product_params[:age]}"
end
private
def product_params
params.permit(:name, :age)
end
end
. As I continue and wrote the request Rspec:
RSpec.describe Api::productsController, type: :request do
it "creates a product" do
post "/api/products", params: { name: "name", age: "22"}
expect(response).to have_http_status(:created)
expect(response.body).to include("product was successfully created.")
end
end
But when I run the request rspec test on the command line I get the following error:
Failure/Error: expect(response).to have_http_status(:created)
expected the response to have status code :created (201) but it was :no_content (204)
My question is how can I set the status code to :created (201)? is the Head method a good approach? any solution or guiding would be appreciated!
It is common to return json presentation of created item.
Now there is no returning data from your action.
Try to use render json: product_params.to_json, status: :created
def create
Rails.logger.info "product was created and the parameters are #{product_params[:name]}, #{product_params[:age]}"
render status: :created
end

API POST request returns 404 route not found

Rails 5.2.2.1
ruby 2.6.3p62
I'm writing an API endpoint that should accept a post request. I created the route:
namespace :api do
scope module: :v1, constraints: Example::ApiVersionConstraint.new(1) do
resources 'books', only: [:create]
end
end
bundle exec rails routes | grep books returns:
api_books POST /api/books(.:format) api/v1/books#create
app/controllers/api/v1/books_controller.rb:
class Api::V1::BooksController < Api::BaseController
attr_reader :book
def create
book = Book.build(title: 'test')
if book.save
render json: book
else
render json: { error: 'error' }, status: 400
end
end
end
server is running on port 3000 and when submitting a POST request to http://localhost:3000/api/books.json using Postman I get this response:
{
"errors": [
{
"code": "routing.not_found",
"status": 404,
"title": "Not found",
"message": "The path '/api/books' does not exist."
}
],
"request": ""
}
lib/example/api_version_constraint.rb:
module Example
class ApiVersionConstraint
def initialize(version)
#version = version
end
def matches?(request)
request.headers.fetch(:accept).include?("version=#{#version}")
rescue KeyError
false
end
end
end
why isn't the request finding the route?
Something is likely failing in ApiVersionConstraint. To troubleshoot you can do something like:
def matches?(request)
byebug
request.headers.fetch(:accept).include?("version=#{#version}")
rescue KeyError
false
end
Guessing it's a problem with how you're targeting the header, so something like this might work:
request&.headers&.fetch("Accept")&.include?("version=#{#version}")
Because you have a rescue clause, you'll never get the full error; only false, so you might try removing that and seeing if you get a more descriptive error.

Need Help Unit Testing with Rails 5 for Update Action Always Fail on assert_equals

i want to test an update action in my rails project. The function is running well, but when i try to unit-test it's always fail. Can you help this?
i'm new with ruby and unit-testing. i've tried with any documentation it still not solve this test.
this is my Content Controller function that i want to test, i use clearance for auth
before_action :require_login
def update
#content = Content.find(params[:id])
if #content.update(content_params)
flash[:notice] = 'success'
redirect_back fallback_location: root_path
else
flash[:notice] = 'fail'
redirect_back fallback_location: root_path
end
end
this is my Content Fixture
one:
id: '1'
about: 'about content'
privacy: 'privacy content'
terms: 'terms content'
this is my test_helper
ENV['RAILS_ENV'] ||= 'test'
require_relative '../config/environment'
require 'rails/test_help'
require 'clearance/test_unit'
class ActiveSupport::TestCase
fixtures :all
end
class ActionDispatch::IntegrationTest
def sign_in_as_user
user = User.create!(email: "example#example.com", password: "letmein")
post session_url, params: {
session: {
email: user.email,
password: user.password
}
}
end
end
And this is my test code
test "should update content" do
sign_in_as_user
content = contents(:one)
put content_url(content), params: { about: { syarat: "updated about", privacy: "updated privacy", terms: "updated terms" } }
content.reload
assert_equal "updated about", content.about
assert_equal "updated privacy", content.privacy
assert_equal "updated terms", content.terms
end
Then i run the test rake test, this is the result
Failure:
ContentControllerTest#test_should_update_content [/Users/abc/Documents/PROJECT/Apps/test-app/test/controllers/content_controller_test.rb:20]:
--- expected
+++ actual
## -1 +1 ##
-"updated about"
+"about content"

Rspec is different from the app

I'm currently working on a Ruby/Sinatra App and now I'm stuck because my rspec testing is not working properly on the controller. But when I tried my API using curl or web the code just works!.
Here are my file, spesificly on that line of code
listproduct_controller.rb
get '/' do
products = Product.all
payload = []
products.each do |product|
payload.push({ :exhibit_name => product.exhibit_name, :icon => product.icon })
end
return {
:status => 'SUCCESS',
:message => 200,
:payload => payload
}.to_json
end
and here are my spec file
listproduct_controller_spec.rb
context "GET to /products" do
before { allow(Product).to receive(:all) }
before { allow(Product).to receive(:find_by) }
it "returns status 200 OK" do
get '/'
puts(last_response)
expect(last_response).to be_ok
end
it "show a list of product's name and its icon" do
get '/'
#products = Product.all.to_a
expect(last_response.body).to include_json(#products)
end
end
When I puts the last_response on spec it shows this
500
{"Content-Type"=>"text/html", "Content-Length"=>"212150"}
#<Rack::BodyProxy:0x0000000480b1d8>
but when im using curl or apps it just works and return
200 status code with the payload
Can anyone help me what I did wrong?
UPDATE :
I solved it, it was the problem on the database, where all the product in the development database were not on the test database so it returns 500 of empty database.

Resources