Ruby return unless block - ruby-on-rails

I've got a field from github webhook - webhook.repository.private - which checks if created repository was private (boolean). I want use return if block to handle scenario:
check if webhook.repository.private is true and if not call new class PublicRepositoryCreated but if this is true - return and execute fields_hash
code below:
def required_fields
PublicRepositoryCreated.new(webhook).call unless webhook.repository.private
fields_hash
end
private
def fields_hash
{
'fields' => {
'summary' => 'summary',
'description' => 'description',
'project' => '123'
}
}
end
Right now it seems that fields_hash is still executed even when webhook.repository.private is false

You have multiple ways of solving your problem.
You can either :
call your function and return
def required_fields
PublicRepositoryCreated.new(webhook).call && return unless webhook.repository.private
fields_hash
end
return your function
def required_fields
return PublicRepositoryCreated.new(webhook).call unless webhook.repository.private
fields_hash
end
use a ternary
def required_fields
webhook.repository.private ? fields_hash : PublicRepositoryCreated.new(webhook).call
end

Related

How to pass :current_user in Graphql resolver

I have QueryType
Types::QueryType = GraphQL::ObjectType.define do
name 'Query'
field :allProjects, function: Resolvers::Projects
end
And Resolver like this
require 'search_object/plugin/graphql'
module Resolvers
class Projects
include SearchObject.module(:graphql)
type !types[Types::ProjectType]
scope { Project.all }
ProjectFilter = GraphQL::InputObjectType.define do
name 'ProjectFilter'
argument :OR, -> { types[ProjectFilter] }
argument :description_contains, types.String
argument :title_contains, types.String
end
option :filter, type: ProjectFilter, with: :apply_filter
option :first, type: types.Int, with: :apply_first
option :skip, type: types.Int, with: :apply_skip
def apply_first(scope, value)
scope.limit(value)
end
def apply_skip(scope, value)
scope.offset(value)
end
def apply_filter(scope, value)
branches = normalize_filters(value).reduce { |a, b| a.or(b) }
scope.merge branches
end
def normalize_filters(value, branches = [])
scope = Project.all
scope = scope.where('description ILIKE ?', "%#{value['description_contains']}%") if value['description_contains']
scope = scope.where('title ILIKE ?', "%#{value['title_contains']}%") if value['title_contains']
branches << scope
value['OR'].reduce(branches) { |s, v| normalize_filters(v, s) } if value['OR'].present?
branches
end
end
end
I want to access current_user in the resolver so i can access current_user.projects not Project.all. I am very new to graphql and learning.
Everything works but i just need to understand the whole flow on how i can get old of the ctx in the resolver.
First you need to set the current_user in the context. This happens in your GraphqlController.
class GraphqlController < ApplicationController
before_action :authenticate_user!
def execute
variables = ensure_hash(params[:variables])
query = params[:query]
operation_name = params[:operationName]
context = {
current_user: current_user,
}
result = HabitTrackerSchema.execute(query, variables: variables, context: context, operation_name: operation_name)
render json: result
rescue => e
raise e unless Rails.env.development?
handle_error_in_development e
end
# ...
end
Once it's done, you can access the current_user from a query (or a mutation) simply by writing:
context[:current_user]
To make things even simpler, you can add a current_user method toTypes::BaseObject (app/graphql/types/base_object.rb) and you'll be able to call current_user from the #resolve methods.
module Types
class BaseObject < GraphQL::Schema::Object
field_class Types::BaseField
def current_user
context[:current_user]
end
end
end

Need of explicit return in `then` for case statement

I have a Sidekiq worker and in it using a case statement:
module Api
def self.authenticate(company_id)
Thread.current['api_company_id'] = company_id
yield if block_given?
ensure
Thread.current['api_company_id'] = nil
end
end
module Apis
class PollTrackableJobWorker
include Sidekiq::Worker
class EDocumentNotDoneError < StandardError; end
class UnhandledCaseError < StandardError; end
def perform(job_id, _invoice_id)
Api.authenticate(1) do
response = Api::TrackableJob.find(job_id).first
case response['status']
when 'done' then return true
when 'error' then return handle_error(response['errors'])
when 'pending' || 'running' then return raise EDocumentNotDoneError
else raise UnhandledCaseError, response
end
end
end
private
def handle_error(exception)
Bugsnag.notify(exception) if defined?(Bugsnag)
end
end
end
#perform method is tested for all possible outcomes. Below, is a case for done:
class PollTrackableJobWorkerTest < ActiveSupport::TestCase
test 'status is done' do
response = {
'type' => 'trackable_jobs',
'id' => 'xxxxx',
'status' => 'done',
'errors' => nil
}
Api.expects(:authenticate).with(1).yields
Api::TrackableJob.stubs(:find).with('xxxxx').returns([response])
assert_equal(true, Apis::PollTrackableJobWorker.new.perform('xxxxx', 123))
end
end
The test passes perfectly.
However, when I use implicit return, it keeps failing (returns nil).
For example, using a private method with an explicit return statement fails
case response['status']
when 'done' then returns_true
# code omitted
end
private
def returns_true
return true
end
or using implicit return fails too
when 'done' then true
Why do I need explicit return for case statements?

How does Rails params parse hash from string

I'm learning Ruby on Rails and got curious how the params method works. I understand what it does, but how?
Is there a built-in method that takes a hash string like so
"cat[name]"
and translates it to
{ :cat => { :name => <assigned_value> } }
?
I have attempted to write the params method myself but am not sure how to write this functionality in ruby.
The GET parameters are set from ActionDispatch::Request#GET, which extends Rack::Request#GET, which uses Rack::QueryParser#parse_nested_query.
The POST parameters are set from ActionDispatch::Request#POST, which extends Rack::Request#POST, which uses Rack::Multipart#parse_multipart. That splays through several more files in lib/rack/multipart.
Here is a reproduction of the functionality of the method (note: this is NOT how the method works). Helper methods of interest: #array_to_hash and #handle_nested_hash_array
require 'uri'
class Params
def initialize(req, route_params = {})
#params = {}
route_params.keys.each do |key|
handle_nested_hash_array([{key => route_params[key]}])
end
parse_www_encoded_form(req.query_string) if req.query_string
parse_www_encoded_form(req.body) if req.body
end
def [](key)
#params[key.to_sym] || #params[key.to_s]
end
def to_s
#params.to_s
end
class AttributeNotFoundError < ArgumentError; end;
private
def parse_www_encoded_form(www_encoded_form)
params_array = URI::decode_www_form(www_encoded_form).map do |k, v|
[parse_key(k), v]
end
params_array.map! do |sub_array|
array_to_hash(sub_array.flatten)
end
handle_nested_hash_array(params_array)
end
def handle_nested_hash_array(params_array)
params_array.each do |working_hash|
params = #params
while true
if params.keys.include?(working_hash.keys[0])
params = params[working_hash.keys[0]]
working_hash = working_hash[working_hash.keys[0]]
else
break
end
break if !working_hash.values[0].is_a?(Hash)
break if !params.values[0].is_a?(Hash)
end
params.merge!(working_hash)
end
end
def array_to_hash(params_array)
return params_array.join if params_array.length == 1
hash = {}
hash[params_array[0]] = array_to_hash(params_array.drop(1))
hash
end
def parse_key(key)
key.split(/\]\[|\[|\]/)
end
end

Custom Rails Validator Always Failing

I'm using a custom validator via rails, but my validator always creates the record but than fails the save check. Why ?
customers_controller.rb
#coupon = Coupon.create(user_unique_identifier: params[:UDID], promo_code: params[:code])
unless !#coupon.save
##always fails here
coupon.rb
validate :one_per_customer, :before => :create
private
def one_per_customer
if self.is_paid_session
return true
else
#coupon = Coupon.where(user_unique_identifier: self.user_unique_identifier, promo_code: self.promo_code).first
if #coupon.present?
errors.add(:user_unique_identifier, 'PROMO CODE ALREADY APPLIED TO THIS DEVICE')
return false
else
return true
end
end
end

Trouble with model query

I am trying to make a search with custom data in this action here below,
def number_price(user_id,to)
user = User.find(user_id)
prices = Price.where(user_id: user_id)
price.each do |price|
if to =~ /^(price.prefix)/
return price."price_#{user_currency.downcase}"
else
return DefaultPrices."price_#{user_currency.downcase}"
end
end
But i having an error with this request here on the line;
return price."price_#{user_currency.downcase}"
Any idea how i can improve this and make it work.. i have a feeling it something silly..
Thank you
I'm not sure how your model looks like
But I guess you are trying to achieve dynamic function call which can be done by
return price.send("price_#{user_currency.downcase}")
Or
return eval "price.price_#{user_currency.downcase}"
Use public_send instead send because public_send invoke only public method on class instance:
class Foo
private
def bar
puts "Hi!"
end
end
=> nil
=> f = Foo.new
=> #<Foo:0x007f83e3813af8>
=> f.bar
=> #NoMethodError: private method `bar' called for #<Foo:0x007f83e3813af8>
=> f.send(:bar)
Hi!
=> nil
class Baz
def bor
puts "Ho!"
end
end
=> nil
=> s = Baz.new
=> #<Baz:0x007f83e2429da8>
=> s.bor
Ho!
=> nil
=> s.public_send(:bor)
Ho!
=> nil

Resources