sunspot search assiocation using joins - ruby-on-rails

here's a list of model and their relation below:
class Section
has_many :students, as: :resource
searchable do
integer :id
join(:first_name, prefix: "student", target: Student, type: :text, join: {from: :resource_id, to: :id})
join(:last_name, prefix: "student", target: Student, type: :text, join: {from: :resource_id, to: :id})
end
end
class Student
belongs_to :resource, polymorphic: true, optional: false
has_many :contact_number, as: :resource
searchable do
text :first_name
text :last_name
integer :id
integer :resource_id
string :first_name
string :last_name
end
end
class ContactNumber
belongs_to :resource, polymorphic: true, optional: false
end
as you can see in my class model Section has many students. I can search student "first_name" and student "last_name" because of the help of joins. is there possible way to search student contact numbers. using of joins??? or what is the workaround to search the contact numbers in Section model?

in my ContactNumber model, i create an another joins
class ContactNumber
searchable do
string :ref_id do
if resource_type == "Student"
[resource.resource_type, resource.resource_id].join("_").downcase()
end
end
end
in my Student model
searchable do
string :ref_id do
[resource_type, resource_id].join("_").downcase()
end
join(:content, prefix: "contact_number", target: ContactNumber, type: :text, join: {from: :ref_id, to: :ref_id})
end
last in my Section class
class Section
searchable do
string :ref_id do
[self.class.name, id].join("_").downcase()
end
join(:content, prefix: "number", target: ContactPerson, type: :text, join: {from: :ref_id, to: :ref_id})
end
end

Related

AssociationTypeMismatch in Rails/GraphQL?

So my data is pretty simple. Books and Users.
class Books
belongs_to :user
end
class Users
has_many :books
end
Users has the following fields:
first_name
last_name
email
Books has the following fields:
author
title
description
My book_type looks like:
Types::BookType = GraphQL::ObjectType.define do
name 'Book'
field :id, !types.ID
field :author, !types.String
field :title, !types.String
field :user, -> {Types::UserType}, property: :user
end
User_type looks like:
Types::UserType = GraphQL::ObjectType.define do
name 'User'
field :id, !types.ID
field :first_name, !types.String
field :last_name, !types.String
field :email, !types.String
end
Mutation_type looks like:
Types::MutationType = GraphQL::ObjectType.define do
name 'Mutation'
field :bookCreate, function: Resolvers::BookCreate.new
end
Book_create file looks like:
class Resolvers::BookCreate < GraphQL::Function
argument :author, !types.String
argument :title, !types.String
argument :description, !types.String
argument :user, !types.Int
type Types::BookType
def call(_obj, args, _ctx)
Book.create!(
author: args[:author],
title: args[:title],
description: args[:description],
user: args[:user]
)
end
end
Then in localhost:3000/graphiql I do the following:
mutation book {
bookCreate(
author: "Test",
title: "Book Test",
description: "Book Description",
user: 2) {
id
author
title
description
}
}
Getting the following:
<ActiveRecord::AssociationTypeMismatch: User(#69982231587660) expected, got 2 which is an instance of Integer(#11387600)>
Where did I go wrong?
So I changed user to user_id and then on the book model did:
belongs_to :user, foreign_key: 'user_id'
Now it works.

Rails 5 update has_many through associates models

I have following models
class TeamPlayer < ApplicationRecord
belongs_to :team
belongs_to :player
belongs_to :role
end
class Team < ApplicationRecord
has_many :team_players
has_many :players, :through => :team_players
end
class Role < ApplicationRecord
has_many :team_players
has_many :players, :through => :team_players
end
class Player < ApplicationRecord
has_many :team_players
has_many :teams, :through => :team_players
has_many :roles, :through => :team_players
end
Basically, I want to assign different roles to different players in a team.
id team_id player_id role_id
2 1 2 1
3 3 2 1
4 1 1 2
What should it look like in my teams_controller.rb to add new player with a role, to update a player with new role and to remove that player from my team?
This is only the start of a possible solution and it is pretty similar to what you have with some model and database validations added. Some of these validations ensure the uniqueness of every three-way relationship (FilledTeamRole), so either the error of attempting to create a duplicate record would need to be handled or you could filter the possible ids of each class that could be selected so that a duplicate cannot be created.
A complete solution would depend on what other associations you want between the Team, Player and Role classes other than one that requires all three. For example, do you want/need an association between Team and Player where a relationship exists between only those two classes without the necessity of a Role (TeamPlayer id: 1, team_id: 1, player_id: 1). If those relationships are desired, then additional code will be needed to achieve this, which I have and can provide as a suggestion.
As far as what your controller would look like, you could use the filled_team_roles controller (or perhaps create a dashboard controller), provide instance variables #teams, #players and #roles to populate drop-down menus for each class within a form to create the filled_team_roles relationship. You could also have additional forms within each of the other classes where, using two drop-downs instead of three with the third value the selected model id of the class whose controller the form is in (e.g. the edit action in the players_controller with drop-downs for team and role)
~/app/models/team.rb
class Team < ApplicationRecord
has_many :filled_team_roles, dependent: :destroy
validates :name, uniqueness: { scope: [:sport, :city] }
scope :by_name_asc, -> { order(name: :asc) }
end
~/app/models/player.rb
class Player < ApplicationRecord
has_many :filled_team_roles, dependent: :destroy
validates_uniqueness_of :ssn
scope :by_name_asc, -> { order(last_name: :asc, first_name: :asc) }
end
~/app/models/role.rb
class Role < ApplicationRecord
has_many :filled_team_roles, dependent: :destroy
validates_uniqueness_of :name
scope :by_name_asc, -> { order(name: :asc) }
end
~/app/models/filled_team_role.rb
class FilledTeamRole < ApplicationRecord
belongs_to :team
belongs_to :player
belongs_to :role
validates :team_id, presence: true
validates :player_id, presence: true
validates :role_id, presence: true
validates :team_id, uniqueness: { scope: [:player_id, :role_id] }
end
~/db/migrate/20170127041000_create_team.rb
class CreateTeam < ActiveRecord::Migration[5.0]
def change
create_table :teams do |t|
t.string :name
t.string :sport
t.string :city
t.string :state
t.string :country
t.timestamps null: false
end
add_index :teams, [:name, :sport, :city], unique: true
end
end
~/db/migrate/20170127041100_create_player.rb
class CreatePlayer < ActiveRecord::Migration[5.0]
def change
create_table :players do |t|
t.string :first_name
t.string :last_name, index: true
t.string :full_name_surname_first
t.string :ssn, index: { unique: true }
t.timestamps null: false
end
end
end
~/db/migrate/20170127041200_create_role.rb
class CreateRole < ActiveRecord::Migration[5.0]
def change
create_table :roles do |t|
t.string :name, index: { unique: true }
t.timestamps null: false
end
end
end
~/db/migrate/20170127051300_create_filled_team_role.rb
class CreateFilledTeamRole < ActiveRecord::Migration[5.0]
def change
create_table :filled_team_roles do |t|
t.timestamps null: false
t.references :team
t.references :role
t.references :player
end
add_index :filled_team_roles,
[:team_id, :player_id, :role_id],
unique: true,
name: 'index_filled_team_roles_unique_combination_of_foreign_keys'
end
end
~/db/seeds.rb
Team.create(name: 'Los Angeles Dodgers', sport: 'baseball', city: 'Los Angeles', state: 'CA', country: 'United States')
Team.create(name: 'New York Yankees', sport: 'baseball', city: 'New York', state: 'NY', country: 'United States')
Team.create(name: 'Chicago Cubs', sport: 'baseball', city: 'Chicago', state: 'IL', country: 'United States')
Team.create(name: 'St. Louis Cardinals', sport: 'baseball', city: 'St. Louis', state: 'MO', country: 'United States')
Player.create(first_name: 'Max', last_name: 'Walker', full_name_surname_first: 'Walker, Max', ssn: '123-45-6789')
Player.create(first_name: 'Homer', last_name: 'Winn', full_name_surname_first: 'Winn, Homer', ssn: '234-56-7890')
Player.create(first_name: 'Will', last_name: 'Steel', full_name_surname_first: 'Steel, Will', ssn: '345-67-8901')
Player.create(first_name: 'Lucky', last_name: 'Snag', full_name_surname_first: 'Snag, Lucky', ssn: '456-78-9012')
Role.create(name: 'pitcher')
Role.create(name: 'catcher')
Role.create(name: 'first baseman')
Role.create(name: 'second baseman')
Role.create(name: 'shortstop')
Role.create(name: 'third baseman')
Role.create(name: 'right fielder')
Role.create(name: 'center fielder')
Role.create(name: 'left fielder')
FilledTeamRole.create(team_id: 1, player_id: 1, role_id: 1)
FilledTeamRole.create(team_id: 2, player_id: 2, role_id: 2)
FilledTeamRole.create(team_id: 3, player_id: 3, role_id: 3)
FilledTeamRole.create(team_id: 4, player_id: 4, role_id: 4)

How can I do search category.name by using elasticsearch in Rails?

My search working fine.
But I have to type "1" or "2" to get results of "roommate" or "sublet".
Model has a column called category_id which is an integer.
Model Category has column :name which is a string.
Thus, I have category_id 1 is having "roommate" and 2 is "sublet"
below is my Housing model:
class Housing < ActiveRecord::Base
extend FriendlyId
friendly_id :title, use: :slugged
include Elasticsearch::Model
include Elasticsearch::Model::Callbacks
belongs_to :user
belongs_to :category
validates :title, :presence => true
validates :category_id, :presence => true
validates :created_at, :presence => false
validates :user_email, :presence => true
validates :description, :presence => false
validates_length_of :title, :maximum => 30
def self.search(query)
__elasticsearch__.search(
{
query: {
# multi_match: {
simple_query_string: {
query: query,
fields: ['title^10', 'category_id']
}
}
}
)
end
end
How can I fix fields: ['title^10', 'category_id'] So user can search "roommate" instead of must search integer "1" to get result of roommate ?
I tried fields: ['title^10', 'category.name'] but not working.
fields: ['title^10', 'category.name'] won't work unless you have correct mapping defined. Elasticsearch doesn't know about your associations. ES is a document store and searches for records using it's own document store. So unless you add your category name to the document stored in ES, you won't be able to search it.
TL;DR
Define a mapping. Example:
mapping dynamic: 'strict' do
indexes :category do
indexes :name
end
indexes :title
end
Here category will now be stored as nested object inside your index and hence is searchable using category.name

How can I create unique relationships based on a model in neo4j.rb?

I have tried to use
has_many :in, :ratings, unique: true, rel_class: Rating
But that unique: true is ignored because I have a model class for the relationship.
How can I make sure that if my Users rate Articles, their rating gets updated instead of added. I'd prefer it if it produces a single query. ;-)
Article.rb:
class Article
include Neo4j::ActiveNode
property :title, type: String
property :body, type: String
property :created_at, type: DateTime
# property :created_on, type: Date
property :updated_at, type: DateTime
# property :updated_on, type: Date
has_many :in, :ratings, unique: true, rel_class: Rating
has_many :in, :comments, unique: true, type: :comment_on
has_one :in, :author, unique: true, type: :authored, model_class: User
end
User.rb:
class User
include Neo4j::ActiveNode
has_many :out, :articles, unique: true, type: :authored
has_many :out, :comments, unique: true, type: :authored
has_many :out, :ratings, unique: true, rel_class: Rating
# this is a devise model, so there are many properties coming up here.
Rating.rb
class Rating
include Neo4j::ActiveRel
property :value, type: Integer
from_class User
to_class :any
type 'rates'
property :created_at, type: DateTime
# property :created_on, type: Date
property :updated_at, type: DateTime
# property :updated_on, type: Date
end
Rating creation inside the article controller:
Rating.create(:value => params[:articleRating],
:from_node => current_user, :to_node => #article)
This has been resolved. You can ensure unique relationships while using an ActiveRel model by using the creates_unique keyword.
per https://stackoverflow.com/a/33153615
For now I found this ugly workaround..
def rate
params[:articleRating]
rel = current_user.rels(type: :rates, between: #article)
if rel.nil? or rel.first.nil?
Rating.create(:value => rating,
:from_node => current_user, :to_node => #article)
else
rel.first[:value] = rating
rel.first.save
end
render text: ''
end
EDIT: cleaner, but with two queries:
def rate
current_user.rels(type: :rates, between: #article).each{|rel| rel.destroy}
Rating.create(:value => params[:articleRating],
:from_node => current_user, :to_node => #article)
render text: ''
end

Query embedded document using slug array in Mongoid

I have 3 models, that all have use the gem - https://github.com/digitalplaywright/mongoid-slug - that creates a _slugs field from the models title field.
I have the slug for one of my articles and I need to find the issue it belongs to. I have tried a whole deal of things, but nothing seems to work.
Any advice on what the correct query is to get the issue that belongs to the article with my article slug?
Query that doesn't work:
p = Publication.find("my-publication")
p.issues.where(:'articles._slugs'.in => ["an-article-slug"]).first
Publication model:
class Publication
# 1. Include mongoid stuff
include Mongoid::Document
include Mongoid::Timestamps
include Mongoid::Slug
# 2. Define fields
field :title, type: String
field :description, type: String
field :published, type: Boolean, default: false
field :live, type: Boolean, default: false
field :show_walkthrough, type: Boolean, default: true
field :subscription_duration, type: String, default: "Subscription Duration"
field :subscription_price, type: String, default: "Price"
field :sell_issues_separately, type: String, default: "Individual Issue Sale"
field :issue_price, type: String, default: "Price"
field :previewed_on_device, type: Boolean, default: false
field :shareable, type: String, default: "Make Articles Shareable Online"
field :urban_airship_key, type: String
field :urban_airship_secret, type: String
field :urban_airship_master_secret, type: String
# 3. Set attributes accesible
attr_accessible :title, :description, :live, :published, :show_walkthrough, :subscription_duration, :subscription_price, :sell_issues_separately, :issue_price, :cover_image_attributes, :logo_image_attributes, :shareable, :urban_airship_key, :urban_airship_secret, :urban_airship_master_secret
# 4. Set slug
slug :title, reserve: ['new', 'edit', 'walkthrough', 'email', 'previewer', 'privacy', 'support', 'manifest', 'feed', 'demo', 'existence', 'switch']
# 5. Set associations
belongs_to :user
embeds_many :issues, order: :created_at.desc, cascade_callbacks: true
end
Issue model:
class Issue
# 1. Include mongoid stuff
include Mongoid::Document
include Mongoid::Timestamps
include Mongoid::Slug
# 2. Define fields
field :title, type: String
field :description, type: String
field :published, type: Boolean, default: false
field :last_push_at, type: DateTime, default: Time.now
field :published_at, type: DateTime, default: Time.now
field :no, type: Integer, default: 0
field :color, type: String
field :free, type: Boolean, default: false
# 3. Set attributes accesible
attr_accessible :title, :description, :published, :last_push_at, :published_at, :no, :color, :free, :cover_image_attributes
# 4. Set slug
slug :title, scope: :publication, reserve: ['new', 'edit', 'publish', 'update_order']
# 5. Set associations
embedded_in :publication
embeds_many :articles, :as => :articleable, :class_name => 'Article', cascade_callbacks: true, order: :no.desc
embeds_one :cover_image, :as => :imageable, :class_name => 'Image', cascade_callbacks: true, autobuild: true
end
Article model:
class Article
# 1. Include mongoid stuff
include Mongoid::Document
include Mongoid::Timestamps
include Mongoid::Slug
# 2. Define fields
field :title, type: String
field :author, type: String
field :lead, type: String
field :body, type: String
field :no, type: Integer
# 3. Set attributes accesible
attr_accessible :title, :author, :lead, :body, :no, :article_image_attributes, :article_images_attributes, :article_images_attributes
# 4. Set slug
slug :title, scope: :articleable
# 5. Set associations
embedded_in :articleable, polymorphic: true
embeds_one :article_image, :as => :imageable, :class_name => 'Image', cascade_callbacks: true, autobuild: true
embeds_many :article_images, :as => :imageable, :class_name => 'Image', cascade_callbacks: true
end
UPDATED With new queries and results
I can get the publication using the query suggestion of #mu below:
I can't get the issue using the same query though:
And here you can see the _slugs field if I take the first article in the first issue of the publication:
What am I doing wrong here? The query seems to work nicely when grabbing a publication. Why doesn't it work nicely when grabbing an issue?

Resources