Database Agnostic 'or' Query in Rails 4.2 Active Record - mysql

I have a scope on a Conversation model which maintains an encapsulation of messages between 2 users. I created a scope to help detect a 'Conversation' (to find or check exist) from two user objects.
I used to have:
validates_uniqueness_of :from, scope: :to
scope :between, -> (from,to) { where('("conversations"."from" = ? AND "conversations"."to" = ?) OR ("conversations"."from" = ? AND "conversations"."to" = ?)', from, to, to, from) }
However, while this worked for SQLite and Postgres; it wasn't working for MySQL. I need to convert this explicit query to either be completely database agnostic, or to be made out of active record relations instead.
I have had a shot at doing it myself using '.or' but I suspect this is only available from Rails 5+ because it gave me a undefined method error when I tried to use it.
Instead I have used:
validates_uniqueness_of :from, scope: :to
scope :between, -> (from,to) { where(from: [from, to], to: [to, from]) }
This code works great (and its actually really fast and succinct) but I am worried that it might be 'weak' - in that technically it could allow for a situation where from == from, to == from - which is supposed to be impossible for my application.
If a conversation is created between 'X' and 'Y', then from: X and to: Y = conversation_id: 3 and if Y messages X, then it should find conversation_id: 3 (since semantically they are the same).
Im happy enough to leave the new 'between' scope as is, but how can I strengthen the validation to ensure that from != to when the records are created (and then it doesn't matter that the query could potentially find conversations to and from the same user).

You could try rails_or, a gem which supports #or method in Rails 3, 4, 5.
Then write your scope as:
scope :between, -> (from,to) { where(from: from, to: to).or(from: to, to: from) }

Related

Django cross-relational query for custom model properties

I wish to use Django's F to easily get cross-relational information. I had a working form of what I wanted before, but I felt it was ugly and so I transitioned to making custom properties for my models as so:
#property
def stage(self):
"""Returns the competition's stage status by date"""
now = timezone.now()
if self.end_date and self.pub_date and self.close_date and self.start_date:
if self.start_date > now:
return "Launched"
elif self.start_date < now < self.end_date:
return "Commenced"
elif self.end_date < now < self.close_date:
return "Scoring"
else:
return "Ended"
return "Inactive"
In the past, I used a huge When/Case block and annotated this in. I prefer 'property' style of doing things because their values don't mess up when aggregating. (Eg. Team counts get overcounted when I do sums etc. and so I have to do them separately)
However, now I get errors when I try to access: (Team->CompetitionTeam->Competition)
F('competitionteam__competition__stage')
Is there a way to do this? The errors are: (When debugging and trying to annotate the above)
django.core.exceptions.FieldError: Cannot resolve keyword 'stage' into field.
Just running straight from my code, it doesn't cough an error immediately after annotating, but only when the QuerySet in question is accessed.
django.core.exceptions.FieldError: Unsupported lookup 'stage' for AutoField or join on the field not permitted, perhaps you meant range?
Note*: There is no error if I am not annotating and just accessing them from the Objects directly.
You can't use F objects to access model properties because F objects are used when the query is accessing the database and the database does not have access to your python code.
My preference is to use annotations, which you said you stopped doing due to overcounting when you have multiple annotations. This happens because Django's default implementation of annotations uses joins instead of subqueries. This is noted in the docs on combining multiple aggregations.
I believe the solution here is to do the annotation using a subquery. The stage property doesn't use any relational data, so you should be able to do that as you were before. For the other annotations you are doing (you mention Team counts and sums) it's hard to show exactly what you need to do without seeing your models and what you want to annotate, but here are the docs on subquery.
You can also use the package django-sql-utils which provides aggregates like SubqueryCount and SubquerySum which work just like Django's built in Count and Sum but are implemented with subqueries instead of joins.

How to unwrap Rep object of Slick in Scala?

I am using Slick for first time, as an FRM tool with Scala and MySQL.
However while writing query with multiple joins, I realised that I can't access some intermediate objects further to filter based on it.
i.e. rep1 here, which is of type Rep[Option[Manufacturer]]]
How can I unwrap this object to Manufacturer so that I can access columns of it ?
val query = product
.joinLeft(manufacturer).on { case (prod, man) => prod.manufacturerid == man.manufacturerid }
.joinLeft(category).on { case ((prod, rep1), cat) => prod.categoryid == cat.categoryid }
// .filter() after this using rep1
Hello Pratik Shah and welcome to Stackoverflow.
I find it useful to think of anything inside a Rep as running in the database (as part of SQL). With that in mind, you don't unwrap a Rep: you use it within a Slick query (and the result of running the query with kind of unwrap in a sense to a plain value).
So if you can access rep1 inside the filter, you can use Slick's operators (e.g., === not ==, note) to use the Option[Manufacturer] value as part of a query. I can't say for sure without running the code but it'll perhaps be something like:
filter { case ((prod, rep1), cat) => rep1.map(_.manufacturerid) === 42 }
... or whatever you want to do with rep1

Rails 4 Validating email uniqueness without case_sensitive

Using Ruby 2.1.0, Rails 4.0.2, MySQL, and OS X, I can't get the validator uniqueness: { case_insensitive: XXX } to work right.
Yes, I realize this is almost, or perhaps precisely, identical to Rails 3. Validating email uniqueness and case sensitive fails. But the answer stream over there goes down a "don't do that" fork, and at least for pedagogic reasons I'd like to actually answer this question. Out of respect for the line taken over there, I've started a new question. Sorry if that's abusive.
My difficulty is that case_sensitive: true and case_sensitive: false produce the same results, even when (AFAICT) they oughtn't.
models/user.rb extract:
class User < ActiveRecord::Base
VALID_EMAIL_REGEX = /\A[\w+\-.]+#akamai\.com\z/i
validates :email, presence: true, uniqueness: { case_sensitive: false }, format: {
with: VALID_EMAIL_REGEX,
message: "Must be an Akamai email address."
}
end
spec/models/user_spec.rb extract:
require 'spec_helper'
describe User do
before { #user = User.new(email: "giuseppe#akamai.com") }
subject { #user }
it { should be_valid }
context "email" do
describe "is already taken (caserifically)" do
before do
user_with_same_email = #user.dup
user_with_same_email.email = #user.email.upcase
user_with_same_email.save
end
it { should_not be_valid }
end
end
end
As written, the test passes (user_with_same_email is not valid). Cool.
However, if I change the validation's false to true, the test still passes (user_with_same_email is still invalid, presumably colliding). Uncool.
I know that MySQL/OSX is case-insensitive as regards table names (due to the case-insensitive underlying file system), but this doesn't extend to value comparisons, does it?
Ooo, just noticed the (unanswered) Ruby on Rails Tutorial - Michael Hartl - Test “User when email address is already taken”. I believe these are exact duplicates.
I don't know about your specific database setup, but yes, I would say that is most likely the issue.
This is a quote from the Rails API guide for :uniqueness:
Note that some databases are configured to perform case-insensitive searches anyway.
http://edgeguides.rubyonrails.org/active_record_validations.html#uniqueness
As far as I can tell, there isn't an official patch for this. Best I can find are these old discussions:
https://github.com/rails/rails/issues/1399
https://github.com/rails/rails/issues/613
Both mention various ways around it.
I'd say your best bet is running it against what your production environment will be like too. Seems it behaves differently on different platforms.
There is an issue with your VALID_EMAIL_REGEX, you must end it with /i to be case insensitive.

Ember.js with Rails accepts_nested_attributes_for and polymorphic has_many/belongs_to

On the Rails API side I have the following 2 models:
class Grower < ActiveRecord::Base
has_many :addresses, as: :addressable
accepts_nested_attributes_for :addresses
end
class Address < ActiveRecord::Base
belongs_to :addressable, polymorphic: true
end
as well as a Growers controller which returns and can create/update Growers with embedded Addresses attributes. I also have an Addresses controller with proper routing so that Addresses can be viewed/created/updated for a specific Grower. The latter is more of an "in-case", and I'm not sure I'll be needing to return/update/create addresses as a separate payload.
I am starting to try and piece together an Ember app that would allow me to view/edit/create a Grower at the same time as its Address(es). Can anyone point me to an existing real or sample app that does this? I will be posting my code as I go along, but I already have an idea of some areas where I will be running into trouble:
Rails returns/expects nested params named addresses_attributes. Ember, I am sure, doesn't use that convention. What's the best approach of resolving this?
Because of the polymorphic association (objects other than Grower can be addressable), on the API/Address side, to get the correct belongs_to object, Rails uses addressable_id in conjunction with addressable_type. In this example the addressable_type would be "Grower", and the addressable_id would be the grower_id value. How would one go about translating that on the Ember side?
UPDATE:
I got it to work at least a couple different ways. My preferred solution, at least for this particular case, is in the answer section.
Here is a sample of code based #yuяi's strategy that worked well for me:
App.Post = DS.Model.extend
comments: DS.hasMany('comment')
App.PostSerializer = DS.ActiveModelSerializer.extend( DS.EmbeddedRecordsMixin,
attrs:
comments: {embedded: 'always'}
keyForAttribute: (attr) ->
if attr == "comments"
"comments_attributes"
else
#_super(attr)
)
This solution worked well with Ember 1.6.1 and Ember Data 1.0.0-beta.8.2a68c63a.
I found a couple ways to get it done, but the final approach doesn't require any changes on the Rails/API side.
On the client (Ember) side:
I added the addresses hasMany property to the App.Grower model. I also mapped it on the RESTAdapter to what's expected from the API, by setting the key for addresses to addresses_attributes.
I added the grower (for now - will change to addressable once I have other addressable models) belongsTo property on App.Address. It's not really required for what I'm doing, but it might be useful in the future.
I set the addresses on the RESTAdapter to be embedded: 'always'.
On the App.GrowersEditController, I just do a model.save (transaction.commit), and the child addresses are automatically saved via the API call.
On the App.GrowersAddController, I use the App.Address.createRecord and App.Grower.createRecord methods using the user-entered Grower and Address data. Then I use the pushObject method to append the Address to the Grower, and then call a save on the Grower (commit on transaction). Again, the address data gets submitted and saved automatically.

Entity Framework Code First Case Sensitivity on string PK/FK Relationships

I have a fairly simple composite one to many relationship defined using POCO/Fluent API, one column of which is a string.
I've discovered that the data in this column in our database is inconsistent in terms of case ie 'abb', 'ABB' - this is our main ERP system and is fed by a variety of sources which are mainly beyond our control.
This is leading to problems using EF code first when joining to related tables as the join is silently ignored by EF when the case of PK/FK is different even though SQL Profiler shows the correct SQL being executed and results returned.
I'm using WCF so have lazy loading and proxy creation turned off and am eager loading required related entities using Include. eg.
var member = context.Member.Include(m => m.Audits).First(m => m.Id == id);
Are there any solutions to this outside of amending the database schema?
EF Insensitive join comparison
Hi I'm having the same problem (although not wit code first, but with a generated model)
The cause is that EF makes a case-sensitive comparison of the key fields, and it doesn'n find the related objects.
I'm guessing the problem lies in the "EDM Relationship Manager" and maybe there's a possibility of overriding this behavior.
I found a simple workaround for this: lower casing the related properties:
[EdmScalarPropertyAttribute(EntityKeyProperty=true, IsNullable=false)]
[DataMemberAttribute()]
public global::System.String id
{
get
{
return _id.ToLower(); // **<- here**
}
set
{
if (_id != value)
{
OnidChanging(value);
ReportPropertyChanging("id");
_id = StructuralObject.SetValidValue(value, false);
ReportPropertyChanged("id");
OnidChanged();
}
}
}
private global::System.String _id;
partial void OnidChanging(global::System.String value);
partial void OnidChanged();
It actually works, but, of course, it's a lame workoround.
I'm sticking to it for a while util I (or somebody) comes out with a better solution.
Good Luck!
I came up with a workaround that manually "stitches up" the association after the context has retrieved the appropriate rows from the database. Translated to your problem it would be along these lines:
//Your original query
var members = context.Member.Include(m => m.Audits).First(m => m.Id == id);
//The "stitch up" code that should probably be moved to a method of the data context.
var membersWithoutAudits = context.Members.Local.Where(m => !m.Audits.Any()).ToList();
foreach (var nextMember in membersWithoutAudits) {
//Now we can populate the association using whatever logic we like
nextMember.Audits = context.Audits.Local.Where(a => a.MemberId.ToLower() == nextMember.Id.ToLower()).ToList();
}
Notice how we use the context.[DbSet].Local property to ensure that we do all the "stitch up" in memory without making any further SQL calls. I also fetch the members without audits as a performance optimization so we are not re-doing the work of EF's association (in the cases where it did work). But you could just as easily remap every "member" instance.