Share common arguments between query types in ruby graphql - graphql-ruby

What's the best way to share some arguments between different query types. I want to share some common arguments like created_at, updated_at
field :products, ProductType.connection_type, null: false do
argument :name, [String], required: false
# <--shared arguments args1-->
# <--shared arguments args2-->
end
field :brands, BrandType.connection_type, null: false do
argument :code, [String], required: false
# <--shared arguments args1-->
end
We could use Resolver but it is not recommended unless absolutely necessary.

Related

Is `orphan_types` the only way to specify possible resolve types for an interface?

The ruby-graphql documentation says the following about resolve types for interfaces:
...a schema finds it types by traversing its fields, starting with query, mutation and subscription. If an object is never the return type of a field, but only connected via an interface, then it must be explicitly connected to the schema via orphan_types.
See here
I have the following definition of a module with two classes that implement it:
module Contact
include GraphQL::Schema::Interface
field :id, ID, null: false
end
class Cmpany < Types::Base
implements Contact
graphql_name "Company"
field :name, String, null: false
end
class Person < Types::Base
implements Contact
graphql_name "Person"
field :first_name, String, null: false
field :last_name, String, null: false
end
As it stands, my code matches the description in the documentation, in that the types Company and Person are never the return type of any field in the schema other than the query which has the interface Contact as its return type. Without any other changes, GraphQL does not recognize the contacts query.
Is orphan_types to interfaces what possible_types is to unions? Perhaps it's the naming that puts me off, but orphan_types seems like a workaround that shouldn't be used. Is it the correct solution?

Beginner Rails Migration & Column Options in ActiveRecord

Quick question on :null option in ActiveRecord table creation.
Let's say I was to create a new table with a column description.
def change
create_table :products do |t|
t.string :name
t.text :description, null: false
end
end
If I don't have any :presence validation in my model regarding the description column, then shouldn't "nothing" be able to be passed into the description column? I'm not sure what null: false can do to stop me from passing nothing in since I don't have any validation in place.
Rails migration or schema options like null: false operate on database level (storage). If you tried to save record with empty description field, you would receive a database error (e.g. generated by PostgreSQL) wrapped in a ActiveRecord::StatementInvalid:. On calling object.valid? the object would have been valid from the application point of view (Rails).
Rails validations like :presence operate on application level. In this case passing a null value would create an object which would return false on valid? and you could easily access error messages from the object by calling object.errors. If not bypassing validations, Rails would not allow you to save such a record to the database.

Extra validations on url before an object is created/saved to prevent SQL injection?

Hopefully this isn't an invalid question, but could someone please explain to me what happens when rails creates and saves an object to the database or updates one? I've put several validations in place, but I'm not sure if I've missed something as there doesn't seem to be too much information on how rails secures its models under the hood.
In this code the user is supplying some data(supposed to be a url), I check with a REGEX to see if it is a url. I'm wondering if I need to do any additional SQL protection techniques for something as complicated as a url?
class ListLink < ActiveRecord::Base
belongs_to :list
default_scope -> {order('created_at DESC')}
#the REGEX urls are matched against
VALID_URL_REGEX = /\A(http:\/\/|https:\/\/|www|)[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(([0-9]{1,5})?\/.*)?\z/i
validates :link_url, presence: true,
format:{with: VALID_URL_REGEX, message: "Please enter a valid url."}
validates :list_id, presence: true
#if is a valid url, ping embedly for more information on it
before_save :embedly #:set_link_info
#not sure what checks rails does on attributes created after validation
#any suggestions on how I can make these safer would be appreciated!
before_create :title, presence: true, length:{minimum: 4, maximum: 200}
before_create :image_url, presence: true
private
def embedly
embedly_api = Embedly::API.new :key => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
:user_agent => 'Mozilla/5.0 (compatible; mytestapp/1.0; my#email.com)'
url = link_url.dup
obj = embedly_api.extract :url => url
#extract and save a title and image element to the database
#are these validated by Rails too?
self.title = obj[0].title
self.image_url = obj[0]["images"][0]["url"]
end
end
Thanks for any help!
No extra care required; validates is enough.
Using ActiveRecord you can be sure the input data is properly escaped.
User.last.update_attributes(first_name: 'DROP TABLE users;')
# => true
User.last.first_name
# => "DROP TABLE users;"
You seems to misunderstand the purpose of before_create. It is a callback that's executed right before the record is added into the database. Its purpose is not to validate the object, but to execute custom code, as in the case with :embedly. You want to change before_create to validates here. The latter is called every time before the object is saved on both create and update actions. If you have
validates :title, presence: true, length:{minimum: 4, maximum: 200}
and your object has a too short title, ActiveRecord won't allow you to save it.
As addition to #shock_one answer:
ActiveRecord will call ActiveRecord::Base.connection.connection.quoute on every property, which will properly escape the values against SQL Injections. Same happens if you use hash queries or question mark placeholders in you queries.
e.g
User.where(name: params[:name])
User.where("name=?", params[:name]).
However if you write your own concatenated sql queries you have to use qoute on user input
c = ActiveRecord::Base.connection
User.where("name=#{c.quote params[:name]}")

Accessing params in validations

I would like to show some extra info in error messages resulting from a failed validation. For example suppose I have a class Book with the following validation
validates :name, presence: true, uniqueness: true
When someone tries to insert a book by the same name the following error message is returned
{"name":["has already been taken"]}
Instead I wanna show
{"name":["Book 'Great Expectaions' has already been taken at id:7"]}
Right now to make this happen I have to remove the uniqueness validation that I mentioned above and do the following
validate do |book|
existing_book = Book.find_by_name(book.name)
if existing_book
book.errors.add(:name, "#{existing_book.name} already exists at id: #{existing_book.id}")
end
end
Is there a way to get custom error messages like above without writing a custom uniqueness validation? I was thinking something along the lines of
validates :name, presence: true, uniqueness: {message: "#{self.name} already exists at id: #{Book.find_by_name(self.name).id}"
But this does not seem to work as self.name returns 'Book'. Is there a way to access the passed parameters in this context?
You'll have to do this as a custom validation. I would do it like so:
validate :name_is_unique
private
def name_is_unique
errors.add(:name, "#{other_book.name} already exists at id: #{other_book.id}") if other_book = Book.find_by_name(name)
end
The issue isn't really that you can't include the current model attributes in your validation, its that there's no 'one-liner' way to include another model. The good news is, that's what the validate method is for.
If it bothers you to have this in your model, just write a custom validator so it can be re-used application-wide.

Validate singularity of a string in rails

Anyone know if there is anything built into rails to the effect of validates_signularity_of :string? I can't find any documentation of anything like this, but just wanted to check. I want to validate that a string the user can enter in is always a singular word.
One way would be to leverage the singularize method.
If singularizing a string results in the same string, the string is already singular. Otherwise, it is plural.
A custom validator like the following might work:
class SingularValidator < ActiveModel::EachValidator
def validate_each(object, attribute, value)
unless value.to_s.singularize == value
object.errors[attribute] << (options[:message] || "is not singular")
end
end
end
Then in your model:
validates :column_name, :singular => true
Credit:
Basic structure of a custom validator extracted from Ryan's Railscast #211