I have an orde field on one of my models, that model also has a is_milestone? method which returns true or false depending on whether the order is either a 50th or 100th milestone.
I wish to select all the items that are milestones but can this be done by using the is_milestone? method?
I currently have:
#milestones = Model.where(:is_milestone?).order('order ASC')
But it doesn't work and I think I have the syntax wrong but unsure how it should be written.
Any thoughts?
No - You cannot ask the database to do a query which requires interaction with your Ruby code.
The only way you'd be able to get this to work is to create an is_milestone attribute on your model and store the boolean value within the database. You could perhaps populate this value with an after_save callback which counted the milestones and set the value to true if it was either the 50th or 100th one.
Related
I'm working in Ruby on Rails 4 with Postgresql, and I've hit a bit of a snag. We have an Active Record model called AttendanceRecord which belongs to an AttendanceDay, AttendanceSwipe, Course, and CourseTimeSlot. Attendance Records were supposed to be unique on these fields, but something went wrong and duplicates snuck in. So, I wrote a method to find all of the Attendance Records which were duplicated and only keep one of them.
In the course of that method, I built an Active Record Relation of objects that shared the same attributes, like so:
records = AttendanceRecord.where(course_id: attributes[0], course_time_slot_id: attributes[1], attendance_swipe_id: attributes[2], attendance_day_id: attributes[3])
Nice relation, right?
Next, I found the object that I wanted to keep and named it to_keep. Then, I tried to remove just that object from the relation, like this:
records.delete(to_keep)
Unfortunately, I discovered that the delete method works a little differently on a Relation than it does on an Array. Instead of simply removing the object from the list, it actually does delete it from the database (without the callbacks).
So: I'm wondering if there is a method that I'm missing that will remove my to_keep object from the Relation without actually touching the object itself. Then, I'll be able to safely call records.destroy_all and happily go about my business. :)
If you want to exclude an object from a relation you can do so by id. For example:
records.where('id <> ?', to_keep.id).destroy_all
or, thanks to #trushkevich, in rails 4 you can do:
records.where.not(id: to_keep.id).destroy_all
This means that destroy_all will be called on the records you've identified already but excluding the to_keep record.
(I tried posting this to the CFWheels Google Group (twice), but for some reason my message never appears. Is that list moderated?)
Here's my problem: I'm working on a social networking app in CF on Wheels, not too dissimilar from the one we're all familiar with in Chris Peters's awesome tutorials. In mine, though, I'm required to display the most recent status message in the user directory. I've got a User model with hasMany("statuses") and a Status model with belongsTo("user"). So here's the code I started with:
users = model("user").findAll(include="userprofile, statuses");
This of course returns one record for every status message in the statuses table. Massive overkill. So next I try:
users = model("user").findAll(include="userprofile, statuses", group="users.id");
Getting closer, but now we're getting the first status record for each user (the lowest status.id), when I want to select for the most recent status. I think in straight SQL I would use a subquery to reorder the statuses first, but that's not available to me in the Wheels ORM. So is there another clean way to achieve this, or will I have to drag a huge query result or object the statuses into my CFML and then filter them out while I loop?
You can grab the most recent status using a calculated property:
// models/User.cfc
function init() {
property(
name="mostRecentStatusMessage",
sql="SELECT message FROM statuses WHERE userid = users.id ORDER BY createdat DESC LIMIT 1,1"
);
}
Of course, the syntax of the SELECT statement will depend on your RDBMS, but that should get you started.
The downside is that you'll need to create a calculated property for each column that you need available in your query.
The other option is to create a method in your model and write custom SQL in <cfquery> tags. That way is perfectly valid as well.
I don't know your exact DB schema, but shouldn't your findAll() look more like something such as this:
statuses = model("status").findAll(include="userprofile(user)", where="userid = users.id");
That should get all statuses from a specific user...or is it that you need it for all users? I'm finding your question a little tricky to work out. What is it you're exactly trying to get returned?
I'm trying to get a "What's new" section working in my Rails app that takes into account new records created for various tables that don't share any relationships. The one thing they do have in common is that they all have a created_at field, which I'm going to use to determine if they're indeed "new" and then I'm wanting to sort the results by that common field. I tried doing this with Sunspot, but I couldn't figure out how to make use of the the result set returned from the Sunspot search...
For instance in my Uploads and Article models I have:
searchable do
time :created_at
end
and in my search action I'll do this:
#updates = Sunspot.search(Upload,Article) do
with(:created_at).greater_than(1.hour.ago)
end
Which does seem to return something, if I do an #updates.total it returns the number of records I was expecting to find. Beyond this I'm not sure how to actually make use of the records. What I'd like to do is send #updates to a view and determine the model type of each record and then proceed to print out the relevant information, i.e names, descriptions, parent/child record information (for instance upload.user.username).
I might be going at this all wrong, perhaps there's a better option than sunspot for the simple search I'm attempting to perform?
Refer readme for details of how to use the search results. The method you are looking for is "results", which will give you first 30 results, by default:
#updates.results # array of first 30 results
In my application Users register for Events, which belong to a Stream. The registrations are managed in the Registration model, which have a boolean field called 'attended'.
I'm trying to generate a leaderboard and need to know: the total number of registrations for each user, as well as a count for user registrations in each individual event stream.
I'm trying this (in User.rb):
# returns an array of users and their attendence count
def self.attendance_counts
User.all(
:select => "users.*, sum(attended) as attendance_count",
:joins => 'left join `registrations` ON registrations.user_id = users.id',
:group => 'registrations.user_id',
:order => 'attendance_count DESC'
)
end
The generated SQL works for just returning the total attended count for each user when I run it in the database, but all that gets returned is the User record in Rails.
I'm about to give up and hardcode a counter_cache for each stream (they are fairly fixed) into the User table, which gets manually updated whenever the attended attribute changes on a Registration model save.
Still, I'm really curious as to how to perform a query like this. It must come up all the time when calculating statistics and reports on records with relationships.
Your time and consideration is much appreciated. Thanks in advance.
Firstly as a couple of points on style and rails functions to help you with building DB queries.
1) You're better writing this as a scope rather than a method i.e.
scope attendance_counts, select("users.*, sum(attended) as attendance_count").joins(:registrations).group('registrations.user_id').order('attendance_count DESC')
2) It's better not to call all/find/first on the query you've built up until you actually need it (i.e. in the controller or view). That way if you decide to implement action / fragment caching later on the DB query won't get called if the cached action / fragment is served to the user.
3) Rails has a series of functions to help with aggregating db data. for example if you only wanted a user's id and the sum of attended you could use something like the following code:
Registrations.group(:user_id).sum(:attended)
Other functions include count, avg, minimum, maximum
Finally in answer to your question, rails will create an attribute for you to access the value of any custom fields you have in the select part of your query. e.g.
#users = User.attendance_counts
#users[0].attendance_count # The attendance count for the first user returned by the query
I don't know if this is possible, but I'm writing an application that allows anonymous users to create records and update them. Now I only want them to be able to update a record within a few minutes after creating it.
Is there any kind of timeout method I can use with, say cancan for example?
Or would a better option be to associate the model with the user's IP address and only let the same IP edit the record? Since the end goal is preventing a malicious user from editing any and all records.
Thanks
You can use callback validation with your own custom function.
If you created model using the rails generate commands, every model will have a created_at column in the database.
Model Book
before_update: check_time
def check_time
if created_at < 10.seconds.ago
return false
else
return true
end
end
end