Rails 4 + Mongoid + API Calls - Unable to define few conditions - api

In my Rails Application, I am trying to built API for one Model but I am not able to execute few methods. Did nt know where is wrong. Please suggest something.
Model - User
class User
include Mongoid::Document
include Mongoid::Timestamps
field :name, type: String
field :display_name, type: String
field :user_type, type: String
field :city_id, type: String
field :country_id, type: String
field :tags, type: String
field :status, type: Mongoid::Boolean
field :rating, type: Array
end
API 1. List of All User - User.All
But I am not able to take select columns name. Tried in model to define scope but still gives error. ie.
User.selected_column
scope :selected_column, -> { select("id, name") }
API 2. List of Top Rated User - User.rating_five
Tried in model to define scope but still gives error. ie.
User.rating_five
scope :rating_five, -> { .where(:rating["average"] > 4.6 ) }

Mondoid DSL is a bit different from that of Activerecord in some cases. Refer official documentation here.
First issue:
scope :selected_column, -> { only(:id, :name) }
Inorder to select specific columns.
For the second issue, try
scope :rating_five, -> { gt('rating.average': 4.6) }
Here gt represents greater than

Related

PRISMA: Getting type error on where clause in update method

Have a specific Prisma ORM library error that I need help with.
I have created a migration and pushed it to a postgres db.
I have generated the client model for Prisma and am able to findAll and insert data using the create method.
Where I am having trouble is the update method.
Here's my code
app.post("/articles/:title", async (req: Request, res: Response) => {
const article = await prisma.article.update({
where: { title: req.params.title },
data: { title: req.body.title, content: req.body.content },
})
res.send('The article was posted sucessfully.' + article)
})
I am getting the following error which makes me think that the client is not finding a type 'title' when using the where argument.
app.ts:65:14 - error TS2322: Type '{ title: string; }' is not assignable to type 'ArticleWhereUniqueInput'.
Object literal may only specify known properties, and 'title' does not exist in type 'ArticleWhereUniqueInput'.
65 where: { title: req.params.title },
~~~~~~~~~~~~~~~~~~~~~~~
node_modules/.prisma/client/index.d.ts:784:3
784 where: ArticleWhereUniqueInput
~~~~~
The expected type comes from property 'where' which is declared here on type 'Subset<ArticleUpdateArgs, ArticleUpdateArgs>'
Has anyone else had this issue?
I tried to introspect the database just to make sure the database was captured exactly as is, with title and content fields and then generated the client again.
Many thanks
James
Found the answer: Post answer was a response from Antonie
The fields in
where
needs to be unique.
If you can make some field, let's say date #unique (date: DateTime! #unique), and use that for your where in the upsert, I think it would work (tested on my local).
Use .(find/update/delete)Many() if you are trying to query with multi values.

Rails force all translations

I am using globalize3 with rails_admin thanks to this gist. What bugs me, is that the user can add as many translations as he wants.
Moreover, he isn't forced to translate the content in every single locale (as in I18n.available_locales). I'd like that. How can you tackle such a situation?
Models (shortened):
class Project < ActiveRecord::Base
has_many :project_translations, :dependent => :destroy, :inverse_of => :project
accepts_nested_attributes_for :project_translations, :allow_destroy => true
class ProjectTranslation < ActiveRecord::Base
belongs_to :project
I ended up using Active Admin plus activeadmin-globalize3 instead. Much easier.
It bugged me too, so I created custom field type that doesn't allow it.
The main class:
module RailsAdmin
module Config
module Fields
module Types
class GlobalizeTabs < RailsAdmin::Config::Fields::Association
RailsAdmin::Config::Fields::Types::register(:globalize_tabs, self)
register_instance_option :partial do
:form_globalize_tabs
end
def method_name
"#{super}_attributes".to_sym
end
# Reader for validation errors of the bound object
def errors
bindings[:object].errors[name]
end
def available_locales
I18n.available_locales
end
def current_locale
I18n.locale
end
# Returns array of Translation objects
# It gets existing or creates new empty translation for every locale
# It's used in fields_for method in partial
def translations
translated_locales = #bindings[:object].translated_locales
available_locales.collect do |locale|
translated_locales.include?(locale) ? #bindings[:object].translation_for(locale) : #bindings[:object].translations.new({ locale: locale })
end
end
end
end
end
end
end
It inherits from RailsAdmin::Config::Fields::Association class, because it uses very similar to _form_nested_many partial (that's used in has_many type).
The partial:
.controls
= form.errors_for(field)
%ul.nav.nav-tabs{ :style => 'margin-top:5px' }
- field.available_locales.each do |locale|
%li{ class: ( 'active' if locale == field.current_locale ) }
%a{ href: "##{locale}", data: { toggle: "tab" } }= locale
.tab-content
= form.fields_for field.name, field.translations, wrapper: false do |nested_form|
.fields.tab-pane{ id: nested_form.object.locale, class: ( 'active' if nested_form.object.locale == field.current_locale ) }
= nested_form.generate({:action => :nested, :model_config => field.associated_model_config, :nested_in => field.name })
= form.help_for(field)
It uses field.translations method from the custom field class, that returns an array of Translation objects.
Every Translation object corresponds to available locale, and it's either an existing object from the database (if translation already exists) or new empty translation object.
E.g.
You've got this available locales:
I18n.available_locales = [:en, :cz, :ru]
You have Page model which includes some translated fields.
Also, you have an object of the class Page (a row in the database), that has translations for :en and :cz locales, but lacks one for the :ru.
So, field.translations method inside _form_globalize_tabs partial returns an array that contains:
2 existing translations for :en and :cz and 1 just initialized translation for :ru.
In the partial I'm passing this array to the fields_for helper method from nested_form gem, that returns 3 fieldsets for every translation object.
You can use this gem, if you don't want to mess with the code yourself: https://github.com/scarfaceDeb/rails_admin_globalize_field

FactoryGirl: How do I create a factory once and use it everywhere even in associations

I have two factories defined (there are others not shown) as follows:
Jobseekers & SavedSearch
FactoryGirl.define do
factory :job_seeker do
type Role::JOB_SEEKER_TYPE
commenced_on { rand(60).days.ago }
end
factory :saved_search do
title { Faker::Company.bs + ' title' }
association :job_seeker
saved_on { rand(10).days.ago }
end
end
If I instantiate a jobseeker using the FactoryGirl step definitions like so:
Given 1 job seeker exists
Then when I do:
Given 3 saved searches exist
I get 3 saved_searches OK, but all with new job_seekers (as it should be, as expressed) - but not what I want.
All searches must reference the first job seeker already instantiated.
How can I reference the original job_seeker factory (already instantiated) in the association with :saved_search.
Using:
cucumber-1.1.9
factory_girl_rails-1.7.0
factory_girl-2.6.4
rails-3.0.12
It does what it's supposed to.
job_seeker { JobSeeker.first || association(:job_seeker) } fixed the problem.

Number validation - reference to another attribute

I need a validation to check whether an attribute is less or equal than another (virtual) attribute of the same record. How can I do that?
Sample code (not working - NoMethodError):
attr_reader :virt
attr_accessible :virt
validates :my_attr, :numericality => {:only_integer => true, :less_or_equal => self.virt}
(please be gentle and explicit, I'm a RoR newb :])
Since those validation lines are going to be executed when the class definition is first encountered, self.virt doesn't exist.
You can usually pass in a lambda/proc instead that will be called at validation time from the scope of the object:
validates :my_attr, :numericality => { :less_or_equal => lambda { virt } }
This still isn't that great, though. A better route would be to just define your own validation method:
validate :my_attr_is_within_range
def my_attr_is_within_range
my_attr <= virtual_attribute
end
This is much cleaner and more explicit. Note that you don't need to use self here since there is no ambiguity (if you were setting you would need the self).

Rails 3 - Pass a parameter to custom validation method

I am looking to pass a value to a custom validation. I have done the following as a test:
validate :print_out, :parameter1 => 'Hello'
With this:
def print_out (input="blank")
puts input
end
When creating an object or saving an object, the output is 'blank.' However, if called directly:
object.print_out "Test"
Test is instead outputted. The question is, why is my parameter not passing properly?
Inside the 'config\initializers\' directory, you can create your own validations. As an example, let's create a validation 'validates_obj_length.' Not a very useful validation, but an acceptable example:
Create the file 'obj_length_validator.rb' within the 'config\intializers\' directory.
ActiveRecord::Base.class_eval do
def self.validates_obj_length(*attr_names)
options = attr_names.extract_options!
validates_each(attr_names, options) do |record, attribute, value|
record.errors[attribute] << "Error: Length must be " + options[:length].to_s unless value.length == options[:length]
end
end
end
Once you have this, you can use the very clean:
validates_obj_length :content, :length => 5
Basically, we reopen ActiveRecord::Base class and implement a new sub-validation. We use the splat (*) operator to accept an array of arguments. We then extract out the hash of options into our 'options' variable. Finally we implement our validation(s). This allows the validation to be used with any model anytime and stay DRY!
You could try
validate do |object_name|
object_name.print_out "Hello"
end
Instead of your validate :print_out, :parameter1 => 'Hello'.