Returning an array graphQL - ruby

I'm currently trying to learn GraphQL but running into a problem. The problem is possibly not understanding the right way in writing my types. When I had my user type as
module Types
UserType = GraphQL::ObjectType.define do
name 'User'
field :id, !types.ID
field :username, !types.String
field :email, !types.String, property: :email_address
field :workspaces, types[Types::WorkspaceType]
end
end
I'm able to return an array of workspaces without a problem. Now the problem comes when I try to return an array of users that are associated with that workspace. My workspace type looks like this
class Types::WorkspaceType < Types::BaseObject
field :id, ID, null: false
field :user_id, ID, null: false
field :name, String, null: false
field :members, types[Types::UserType]
end
When I try to run the query in fetching the workspace I'm getting an error that says
"error": {
"message": "undefined local variable or method `types' for Types::UserType:Class",
The backend I'm using is Ruby on Rails. For those with some experience with GraphQL, I would love feedback in what I'm doing wrong and also what is the right way in connecting types between each model. If there are any extra information you'll need or want clarification with please feel free to ask.
Thank you.

The graphql gem has two different "styles" of declaring GraphQL objects using a Ruby DSL (and it can also directly import the GraphQL schema language). The older style (now expunged from the docs) uses GraphQL::ObjectType.define, and needs to qualify most references with the types syntax. The newer style uses Ruby class inheritance, and doesn't use types.
In short: I think your code will work if you just change the last field definition to
field :members, [Types::UserType]

Related

Understanding how ActiveRecord exists? works when building an association

I have two models that are associated via a has_many relationship. E.g.
class Newspaper < ActiveRecord::Base
has_many :articles
end
class Article < ActiveRecord::Base
belongs_to :newspaper
validates :uid, presence: true,
uniqueness: { case_sensitive: true }
end
A newspaper is updated several times a day but we only want to construct and add articles to the association that do not already exist. The following code was my first cut of achieving this.
new_articles.each do |article|
unless newspaper.articles.exists? uid: article.uid
newspaper.articles.build(uid: article.uid)
end
end
The newspaper object is either new and unsaved, or retrieved with existing relationships at this point.
My tests indicate that I am able to add two articles to the newspaper that have the same UID using the code above and this is obviously not want I want.
I appears to me that my current code will result in a validation failure upon being saved as the validation looks at uniqueness across the entire articles table and not the association.
What I'm struggling to understand is how the exists? method behaves in this scenario (and why it's not saving my bacon as I planned). I'm using FactoryGirl to build a newspaper, add an article and then simulate an update containing an article with the same uid as the article I've already added. If the code works I should get only one associated article but instead I get two. Using either build or create makes no difference, thus whether the article record is already present in the database does not appear to change the outcome.
Can anyone shed some light on how I can achieve the desired result or why the exists? method is not doing what I expect?
Thanks
The association exists? actually creates a scoped query, as per the association. This is why your existing articles filter doesn't work.
unless newspaper.articles.exists? uid: article.uid
# `articles.exists?` here will produce this if the newspaper is new
# ... WHERE "articles"."newspaper_id" IS NULL AND "articles.uid" = '<your uid>'
# and this, if the newspaper is persisted (with an id of 1)
# ... WHERE "articles"."newspaper_id" = 1 AND "articles.uid" = '<your uid>'
The case of the new newspaper is clearly wrong, as it would only return articles with a nil newspaper ID. But the persisted case is probably undesirable as well, as it still unnecessarily filters against newspaper ID, when you real concern here is that the UID is unique.
Rather, you probably want simply against Article, rather than scoping the exists? through the association, like:
unless Article.exists? uid: article.uid
Concerning your other problem:
this appears to be a FactoryGirl problem where the create method isn't creating db entries in the same way I can in the irb.
FactoryGirl.create should still abide by validations. It might help to see your test.

Mongoid and Full_text search issue

I have been working on rails project, which had been made using noSql(Mongoid). Every thing is running fine.The issue is I want to add.. full text search here also. I had been using this gems for this...
gem 'mongoid_fulltext'
and my model file looks like this..
class Keyword
include Mongoid::Document
include Mongoid::FullTextSearch
field :name, type:String
#index :name, unique: true
embeds_many :posts
validates_presence_of :name
validates_uniqueness_of :name
fulltext_search_in :name, :index_name => 'name_index'
end
and in controller.
#keywords = Keyword.fulltext_search(params[:search], :index => 'name_index')
and then #keywords always returns an empty array always.
Thanks
Awieet
Apart from what I'm assuming are formatting errors, the only mistake I can find is that you seem to be naming the index manually.
Maybe in your fulltext_search call you should use :index_name => 'name_index' instead of :index => 'name_index'.
I'd advise just not messing with the default name of the index though, and removing that argument entirely from the method call.
Also, were the records persisted before you added the mongoid_fulltext gem? If so you'll need to call the update_ngram_index method on the Class object (or each instance) to add them to the index.
Other than that, have you checked out the mongoid_search gem as an alternative to mongoid_fulltext?
https://github.com/mauriciozaffari/mongoid_search
I've tried both and find find that this one has a much cleaner implementation and interface. Then again, I only use fulltext search sparingly. You may be using fulltext search more than I, and I'm not sure what the differences are feature-wise, but worth a look.
Hope that helps.

Mongoid equivalent of ActiveRecord's `serialize` method

hope the title's pretty self-explanatory.
I'm using mongoid as my ORM for a Rails app, and I was wondering if anybody knew if it has an equivalent to ActiveRecord's serialize method. I've looked through the mongoid documentation but haven't been able to find anything yet.
Here's an example of the model:
class Foo
include Mongoid::Document
field :params, type: String
serialize :params # method from ActiveRecord
end
Thanks in advance!
You don't need to serialize with MongoDB as far as you can store in fields Arrays and Hashes.
field :hash_params, type: Hash
field :array_params, type: Array
Sometimes you need use the Value Object pattern and the same function like composed_of, some people wants to deprecate this function in the future and than you want to use serialize of standard active record. Mongoid provide the same functionality to create Value object avoid the serialize method look , you can provide your custom serialization here http://mongoid.org/en/mongoid/docs/documents.html#custom_fields:
class Foo
include Mongoid::Document
field :params, type: String
field :custom_params , type: MyCustomParamsType
end

How to get activerecord associations via reflection

For normal columns, you can get at them via the columns class method. However, associations may be named something quite different if the foreign_key option is set in the relationship method. For example, given
class Post
has_many :comments, :foreign_key => :message_id # this is a contrived example
end
if I did Post.column_names I could get at message_id, but is there any way to get comments?
Model.reflections gives information about a model's associations. It is a Hash keyed on the association name. e.g.
Post.reflections.keys # => ["comments"]
Here is an example of some of the information it can be used to access:
Post.reflections["comments"].table_name # => "comments"
Post.reflections["comments"].macro # => :has_many
Post.reflections["comments"].foreign_key # => "message_id"
Note: this answer has been updated to cover Rails 4.2 based on MCB's answer and the comments below. In earlier versions of Rails the reflection's foreign_key was accessed using primary_key_name instead, and the keys for the reflections may be symbols instead of strings depending on how the association was defined e.g. :comments instead of "comments".
For future Googlers in Rails 4 the answer would now be:
Post.reflections[:comments].foreign_key # => "message_id"
Taken from here: https://stackoverflow.com/a/15364743/2167965
EDIT:
reflections, as of 4.2, now takes strings instead of symbols which is a fun bug to track down. If you want to keep using symbols you should switch to reflect_on_association(:assoc_name). Also note reflections are actually the public api which will keep reporting things like HABTM, even though it's all has many through under the hood. The reflections Rails is actually using are now in _reflections
For an ActiveRecord object I use:
object._reflections
So, I can manipulate the Hash returned. For instance:
object._reflections.keys.each do |key|
object.public_send(key).destroy_all
end
The above example delete all the relationships from database.

Validating nested models?

To be more specific, "How do I validate that a model requires at least x valid associated models to be created?". I've been trying to validate nested models that get created in the same form as the parent (and ultimately show immediate validations a la jQuery). As a popular example, lets assume the following models and schema.
class Project
include DataMapper::Resource
property :id, Serial
property :title, String, :nullable => false
has 2..n, :tasks
end
class Task
include DataMapper::Resource
property :id, Serial
property :project_id, Integer, :key => true
property :title, String, :nullable => false
belongs_to :project
end
All the validations are done in the schema definitions, as you can see. The important one here is "has 2..n, :tasks". This validation actually works normally, given that the nested task attributes in the params hash will produce valid tasks. If they produce an invalid task, however, then the task won't get created and you'll end up with a Project that has less than 2 tasks, and thus an invalid project object.
As I understand it, this is because it can't figure out if the task attributes are valid or not until it attempts to save the tasks, and since - as far as I know - the tasks can't get saved before the project, the project is unaware if the tasks will be valid or not. Am I correct in assuming this?
Anyway, I was hoping there would be a quick answer, but it seems a lot less trivial then I'd hoped. If you've got any suggestions at all, that would be greatly appreciated.
I actually found a nice solution here using transactions in DataMapper. Basically this transaction tries to save the parent object as well as all the child objects. As soon as one fails to save, then the transaction stops and nothing gets created. If all goes well, then the objects will save successfully.
class Project
def make
transaction do |trans|
trans.rollback unless save
tasks.each do |task|
unless task.save
trans.rollback
break
end
end
end
end
end
This assures that everything is valid before it anything gets saved. I just needed to change my #save and #update methods to #make in my controller code.
SET CONSTRAINTS DEFERRED might be useful if your database engine supports that.
Otherwise, maybe write a stored procedure to do the inserts, and then say that its the resonsibility of the stored procedure to ensure that only correct, validated data is inserted.
There is a model method valid? that runs the validations on a model object before it is saved. So, the simple way to validate the associations would be to use validates_with_block' or 'validates_with_method to check the validations on the associations.
It would look something like this
validates_with_block do
if #tasks.all?{|t|t.valid?}
true
else
[false, "you have an invalid task"]
end
end
Or you could look at dm-association-validator or dm-accepts-nested-attributes
Edit: for extra crazy. run validations on the tasks, then check to see if the only errors are ones related to the association.
validates_with_block do
if #tasks.all?{|t|t.valid?;!t.errors.any?{|e|e[0]==:project}}
true
else
[false, "you have an invalid task"]
end
end

Resources