Simple query needs to move to a model - mysql

I have a simple mysql query I need to put in my admin. It shows a list of banned customers, as well as their name, notes field, and email. We have queries all over the place in this antiquated rails 2.3 app. Although I'm new to rails, I'm pretty sure this needs to live in the Customer model. I know how to build the table in the view, I'm just not sure on the syntax for the model, should it be a named scope, instance, yata yat ya...any recommendations or help would be more than welcome!
SELECT first_name, last_name, notes, email_primary
FROM customer
WHERE banned = 1

A named scope is appropriate:
class Customer
named_scope :banned, :conditions => {:banned => true}
end
Customer.banned # returns a collection of banned customers

Related

Looking for correct query for where.not.any in Rails ActiveRecord

Beginner Rails Question.
I have a table of Users and a table of Teams.
A User has many teams and Teams belong to User.
I want to query if a user does not have a team.
I'm using this query:
User.joins(:teams).where.not(teams: {team_name: 'coconuts'})
This works except if the user has more than one team.
For example User Bill is on the coconuts team and the breadfruit team.
The above query returns Bill when he should be excluded because he is on the coconuts team.
I see why this is happening but I'm having trouble thinking of another query that will work for this scenario.
What is the correct way to grab this data?
I'm using Rails 4.
Try to the following, please consider simple and clean code vs performance:
team = Team.find_by(name: 'coconuts')
excluded_user_ids = team.user_ids
User.where.not(id: excluded_user_ids)
# If you want more a little bit efficiently and suppose you have the join model `Membership`
excluded_user_ids = team.memberships.pluck(:user_id)
# Or if you want more efficiently (just 1 query) and suppose you're using Postgresql
User
.left_outer_joins(:teams)
.group('users.id')
.select("users.*, count(teams.id) AS count_foo, count(teams.id) filter (where teams.name = 'coconuts') AS count_bar")
.having('count_foo != count_bar')
Using just Ruby, and not active record, you can do
User.select {|user| user.teams.pluck(:team_name).exclude?('coconuts')
}

check if a record exists in rails

I have a people table used to track user online activities. I'd like to check if any user from a group is online or not with following query:
Person.where(:person_id => candidates, :online => true).present?
notes: candidates present the group of people; online attribute will be true if user is online
I realize such query is not efficient enough because it returns all the qualified users then check presence. Is there any better way to do the same thing more efficiently?
Thank
Using a COUNT query would be more efficient:
Person.where(:person_id => candidates, :online => true).count
You can then just compare with 0:
Person.where(:person_id => candidates, :online => true).count > 0
you could do something like:
people = Person.select(:id, :online).where(id: candidate_ids)
then unless people.blank? loop through people and check whether they are online and do whatever you need to do with the people who are online. Using select doesn't load the entire object, only the things you need. Then when you say:
person.online
It's not a query, you're just getting it from an array. As a bonus, if you only have an individual user, .select also works with .find.

Using OR query in rails devise omniauth for multiple users

I would like to be able to sign a user in with omniauth and devise from multiple accounts. In my user model I have set the twitter user's uid to equal uid and the provider = twitter. For the user's Facebook uid would equal uid2 and provider2 = Facebook.
I currently use this query to either sign a user in if auth.slice = provider, uid or register them if not.
where(auth.slice(:provider, :uid)).first_or_create do |user|
However now I want to run something similar to:
where(auth.slice(:provider, :uid || :provider2, :uid2 )).first_or_create do |user|
I.e where auth.slice = :provider, :uid OR :provider2, :uid2
essentially I need to be able to run an OR query.
Any help will be much appreciated.
Firstly, the auth.slice(:provider, :uid) is referring to keys in the auth hash from omniauth but provider2 and uid2 are only columns in your db, so they can't be used in the slice in any way as they aren't keys in the auth hash (though I realise that was only an illustration/example of yours). You'd need to extract the hash entries and compare with provider and uid columns and provider2 and uid2 columns separately. Also, to do an OR, you could either use the old-school approach of SQL snippets:
Users.where('(provider = :provider AND uid = :uid) OR (provider2 = :provider AND uid2 = :uid', {provider: auth[:provider], uid: auth[:uid]})
or use AREL, as the bog-standard where can't handle OR. The AREL readme is quite readable https://github.com/rails/arel -- you could do something like:
prov = auth[:provider]
uid = auth[:uid]
users = Arel::Table.new(:users)
users.where(users[:provider].eq(prov).and(users[:uid].eq(uid))).or(users[:provider2].eq(prov).and(users[:uid2].eq(uid)))).project(Arel.sql('*'))
However, I think the long-windedness of both of these highlights that the approach of adding sets of columns per-provider makes things a bit of a pain and it would get worse if, for example, you add login via google, yahoo or whatever, resulting in provider3, uid3 and provider4, uid4... An alternative is to have another model/table which stores these different identities, with a has_many relationship with users. For example:
class User < ActiveRecord::Base
has_many :identities
...
end
class Identity < ActiveRecord::Base
belongs_to :user
...
end
Then you could look up by identities using a simple
Identity.where(auth.slice(:provider, :uid))
like you do now, and not have to worry about adding new providers. They would just result in another row in the identies table related to the relevant user. You could join with users or however you want to handle getting the associated user.

CakePHP Displaying Field Names via Two Associations

I apologize for the confusing title, I was a little stumped as to how to word my question.
I am new to CakePHP, but am following along through the cookbook/tutorials nicely, however I have come up against something which I cannot find an answer to.
My structure is as follows:
'Invoices' hasMany 'InvoiceHistory'
'InvoiceHistory' belongsTo 'InvoiceHistoryDeliveryStatus'
Whereby, an invoice can have multiple invoice histories, and each history contains a delivery status id, which links to a name.
On the Invoice view (index.ctp) I am displaying a list of all invoices but wish to display the Most Recent Delivery Status Name (InvoiceHistory contains a date field so it can be sorted) - thereby displaying the 'current Delivery Status'.
When I do:
$this->set('invoices', $this->Invoice->find('all'));
It does not go deep enough in what it returns to provide me with Delivery Status Names, nor have I deduced a way of only returning the most recent Invoice History within my result. I know how to do this manually with a MYSQL query but I figured that is probably just plain wrong.
What is the correct way of going about this while following CakePHP conventions?
Use Containable
$this->Invoice->Behaviors->attach('Containable');
$this->set('invoices', $this->Invoice->find('all', array(
'contain' => array(
'InvoiceHistory' => array(
'InvoiceHistoryDeliveryStatus'
)
)
));
From what I can tell, I think you should check out the Containable behavior.

Redmine's "latest projects" criteria

When there are more than 5 projects registered on Redmine, those listed on main page's "Latest projects" box are sorted by creation date descending (more recently created first), leaving old projects (which could have been more often updated) out of the list.
Is there a way to list top 5 projects by activity from highest to lowest, or display all registered projects, in that very box, without changing code ? (I don't have access to it).
My version is Redmine 1.0.1.devel (MySQL).
Thank you.
You can change the code in app/models/project.rb to say something different where it says 'count=5' change it to something like 'count=20':
# returns latest created projects
# non public projects will be returned only if user is a member of those
def self.latest(user=nil, count=5)
find(:all, :limit => count, :conditions => visible_by(user), :order => "created_on DESC")
end
If you don't have access to the code then you'll have to just keep using the drop down menu instead.
Browsing around the redmine source for 1.0, it looks like there's no setting for sort order:
http://redmine.rubyforge.org/svn/branches/1.0-stable/app/controllers/welcome_controller.rb