Forum https://discourse.hanamirb.org – Code of Conduct http://hanamirb.org/community/#code-of-conduct
depfu[bot] on update
depfu[bot] on update
Update dry-types to version 1.5… (compare)
depfu[bot] on update
Update dry-struct to version 1.… (compare)
Hi. Please help me to understand how to organize my architecture better. Imagine I have a feature that requires to touch several repositories, models and so on. For example, I have a function CreateTransaction(from_account, to_account, amount)
which does the next things: create debit Transaction on to_account, create credit Transaction of from_account. This operation has some restriction: the amount cannot be 0 or negative, the accounts should be different and so on. So, I need some validations.
The validations are described only in scope of actions (I like having data validations dependent on ,let's say, the protocol level). But of course the CreateTransaction logic must not be implemnted in an action as it might be used from several protocols: from web gui, from json API, from protobuf api and so on
But of course I can create just my own class with an instance method "call" and put some if
conditions:
class CreateTransactionOperation
def initialize(from, to, amount)
end
def call
return :error_1 if amount <= 0
return :error_2 if from == to
begin_transaction
bla bla bla
bla bla
commit_transaction
end
end
and it will work obviously.
get "/users", to: Actions::V1::Users::Index.new
Actually the team is working hard on v2
Sure! But why it's like invisible for the others?
https://github.com/hanami/hanami/releases/tag/v2.0.0.alpha1
30 Jan 2019
self.body=
setter doesn't seem to work. This works. Feels like I'm not doing something correctly, though
HI, I noticed a problem during migration execution, basically I've got migration like this:
Hanami::Model.migration do
change do
create_table :users do
primary_key :id
column :email, String, null: false
column :encrypted_password, String
column :phone_number, String
column :created_at, DateTime, null: false
column :updated_at, DateTime, null: false
end
end
end
When I run it, it shows me following snippet
[hanami] [ERROR] PG::UndefinedTable: ERROR: relation "schema_migrations" does not exist
LINE 1: SELECT NULL AS "nil" FROM "schema_migrations" LIMIT 1
^: SELECT NULL AS "nil" FROM "schema_migrations" LIMIT 1
[hanami] [INFO] (0.042149s) CREATE TABLE "schema_migrations" ("filename" text PRIMARY KEY)
[hanami] [ERROR] PG::UndefinedTable: ERROR: relation "schema_info" does not exist
LINE 1: SELECT NULL AS "nil" FROM "schema_info" LIMIT 1
^: SELECT NULL AS "nil" FROM "schema_info" LIMIT 1
But, when I add null: true
to encrypted_password
and phone_number
everything works smoothly. Both in hanami guide and in rom-sql I see this is an optional attribute. Anyone has idea what can cause this issue?
schema_migrations
and schema_info
exist, if they don't they are created.
Hi, thank you @inouire_twitter and @kaikuchn for responding me. I'll verify if there is no invisible char when in the evening. Also, this is the only migration I have.
About the errors and checks - what I see is in related database schema_migrartions
table is being created but no schema_info
is present. Also, running hanami db prepare
once again, on already migrated database, the output of execution remains the same.
Hello, I'm using hanami-api and hanami-controller (action) as standalone gems. Now I observe an issue and hope somebody can help me. I have a GraphQL-controller, which should use the Authorization-Header
to authenticate. So in the controller I get the header-value as described in the docs:
bearer_token = request.env['HTTP_AUTHORIZATION']
this works for the first request after application-startup. If I change the header at the client application (i.e. to an invalid token). The controller gets always the token from the first request. So the header get cached. If I investigate the whole rack.env
,
ap(request.env)
I get something like this:
{
"rack.version" => [
1,
6
],
"rack.errors" => #<Rack::Lint::ErrorWrapper:0x000055bd2bc60b68 @error=#<IO:<STDERR>>>,
"rack.multithread" => true,
"rack.multiprocess" => false,
"rack.run_once" => false,
"SCRIPT_NAME" => "",
"QUERY_STRING" => "query=query%20($id:%20ID!)%20%7B%0A%20%20airport(id:%20$id)%20%7B%0A%20%20%20%20id%0A%20%20%20%20iataCode%0A%20%20%20%20name%0A%20%20%7D%0A%7D&variables=%7B%22id%22:1%7D",
"SERVER_PROTOCOL" => "HTTP/1.1",
"SERVER_SOFTWARE" => "puma 5.0.4 Spoony Bard",
"GATEWAY_INTERFACE" => "CGI/1.2",
"REQUEST_METHOD" => "GET",
"REQUEST_PATH" => "/graphql",
"REQUEST_URI" => "/graphql?query=query%20($id:%20ID!)%20%7B%0A%20%20airport(id:%20$id)%20%7B%0A%20%20%20%20id%0A%20%20%20%20iataCode%0A%20%20%20%20name%0A%20%20%7D%0A%7D&variables=%7B%22id%22:1%7D",
"HTTP_VERSION" => "HTTP/1.1",
"HTTP_HOST" => "localhost:9292",
"HTTP_USER_AGENT" => "Mozilla/5.0 (X11; Linux x86_64; rv:84.0) Gecko/20100101 Firefox/84.0",
"HTTP_ACCEPT" => "application/json, text/plain, */*",
"HTTP_ACCEPT_LANGUAGE" => "en-US,en;q=0.5",
"HTTP_ACCEPT_ENCODING" => "gzip, deflate",
"HTTP_AUTHORIZATION" => "Bearer old_token",
"HTTP_CONNECTION" => "keep-alive",
"HTTP_COOKIE" => "MicrosoftApplicationsTelemetryDeviceId=cd5cc910-fc4f-436e-8ea7-f93b17fd7093; MicrosoftApplicationsTelemetryFirstLaunchTime=2020-01-08T14:59:29.306Z",
"puma.request_body_wait" => 0,
"SERVER_NAME" => "localhost",
"SERVER_PORT" => "9292",
"PATH_INFO" => "/graphql",
"REMOTE_ADDR" => "127.0.0.1",
"puma.socket" => #<TCPSocket:(closed)>,
"rack.hijack?" => true,
"rack.hijack" => #<Proc:0x000055bd2bc60ff0 /home/armwur/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/rack-2.2.3/lib/rack/lint.rb:567>,
"rack.input" => #<Rack::Lint::InputWrapper:0x000055bd2bc60b90 @input=#<Puma::NullIO:0x000055bd2c024a88>>,
"rack.url_scheme" => "http",
"rack.after_reply" => [],
....
@_env={"rack.version"=>[1, 6], "rack.errors"=>#<Rack::Lint::ErrorWrapper:0x000055bd2ce5e158 @error=#<IO:<STDERR>>>, "rack.multithread"=>true, "rack.multiprocess"=>false, "rack.run_once"=>false, "SCRIPT_NAME"=>"", "HTTP_AUTHORIZATION"=>"Bearer new_token", "QUERY_STRING"=>"query=query%20($id:%20ID!)%20%7B%0A%20%20airport(id:%20$id)%20%7B%0A%20%20%20%20id%0A%20%20%20%20iataCode%0A%20%20%20%20name%0A%20%20%7D%0A%7D&variables=%7B%22id%22:1%7D", "SERVER_PROTOCOL"=>"HTTP/1.1", "SERVER_SOFTWARE"=>"puma 5.0.4 Spoony Bard", "GATEWAY_INTERFACE"=>"CGI/1.2", "REQUEST_METHOD"=>"GET", "REQUEST_PATH"=>"/graphql", "REQUEST_URI"=>"/graphql?query=query%20($id:%20ID!)%20%7B%0A%20%20airport(id:%20$id)%20%7B%0A%20%20%20%20id%0A%20%20%20%20iataCode%0A%20%20%20%20name%0A%20%20%7D%0A%7D&variables=%7B%22id%22:1%7D", "HTTP_VERSION"=>"HTTP/1.1", "HTTP_HOST"=>"localhost:9292", "HTTP_USER_AGENT"=>"Mozilla/5.0 (X11; Linux x86_64; rv:84.0) Gecko/20100101 Firefox/84.0", "HTTP_ACCEPT"=>"application/json, text/plain, */*", "HTTP_ACCEPT_LANGUAGE"=>"en-US,en;q=0.5", "HTTP_ACCEPT_ENCODING"=>"gzip, deflate", "HTTP_CONNECTION"=>"keep-alive
Instantiating a request for each incoming HTTP request can lead to minor performance degradation. As an alternative, please consider getting the same information from private action methods like accept? or from the raw Rack environment params.env.
params.env['HTTP_AUTHORIZATION']
returns everytime the current Auth-Header.