acts_as_list upper_limit on position - ruby-on-rails-5

I am using acts_as_list on my model.I have a position column on that model for which I don't wan't the model object to be saved to the database if the position is more than my upper-limit.(I tried using rails validation for position, but apparently it seems that rails validation runs first then acts_as_list does it's job to update(increment) the position and save it in db.
Is something like this possible with acts_as_list scope: :widgets, {0 < :position <= 2}
I went through their documentation, but couldn't find anything.
How can I do it in Rails.
Any help will be much appreciated. please feel free to ask me for more info if you need.

I think you need to do something like this
acts_as_list scope: :widgets, if: 'position <= 2'

acts_as_list doesn't support this natively. You could try adding a validation based on there being no more than x records with the matching scope?
validates :maximum_records
private
def maximum_records
if where([[scope conditions]]).count > something
errors.add :base, 'too many records'
end
end

Related

How do I retrieve a random GET request in Ruby on Rails 5?

I've created my REST API based on Michael Scott from the Office, so far if you go onto the main part of the API it displays all the quotes /api/v1/quotes/ and you can get individual ones if you add an id number such as /api/v1/quotes/5,but I want users to be able to get a random quote when they put in a GET request.
This would preferably be done with an extra part of the URL such as /api/v1/quotes/random.
I've looked at a lot online but I can't figure this out. Do I put my code into the quotes controller and create another function or do I have to put this somewhere else such as routes.db? Also do I put in the SQL function of RANDOM or is there a better and more efficient way to randomise it. My database only has 50 records in it and it's done in mysql2.
Thanks in advance.
It's my first time posting here as usually I hate asking for help as I think I can always figure it out myself but I'm extremely new to Ruby so I'm fairly clueless on how to solve this. If you need me to clarify my question then just let me know.
You can do that in Model as well as controller.
Model:
class Model < ApplicationRecord
def self.random
Model.limit(1).order("RANDOM()").first
end
end
Controller: In method show
def show
render json: Model.find_by(id: params[:id]) || Model.random
end
I hope that helpful.
I would configure a quotes/random collection route:
# in config/routes.rb
resources :quote do
get 'random', on: :collection
end
and use a controller method like this:
# in controllers/quotes_controller.rb
def random
#quote = Quote.order('RAND()').first
render :show
end
Please note: Returning a single random row from a table is database specific – for MySQL
ORDER BY RAND() LIMIT 1
seems to be the way to go.

activerecord - Time format

This has got to be extremely simple but I'm banging my head against the wall trying to find an answer. I want to find the last updated record using the instance method shown below.
class Subject < ActiveRecord::Base
has_many :assignments, :dependent => :destroy
def get_last_assignment_date
#last_date = self.assignments.select("date_assigned").last
#last_day = #last_date.wday
end
Where my assignments model looks like this:
create_table "assignments", :force => true do |t|
t.date "date_assigned"
<snip>
But Rails returns the following error for get_last_assignment_date:
undefined method `wday' for #<Assignment date_assigned: "2012-08-30">
I need to convert the value returned by active record to a Time format that Ruby can handle but I can't figure out how to do it and it seems to be so easy that no one has even bothered to write how to do it. I would greatly appreciate it if someone could point me in the right direction.
This:
self.assignments.select("date_assigned").last
returns an Assigment object, not a Time object.
So, instead of:
#last_day = #last_date.wday
you have to do:
#last_day = #last_date.date_assigned.wday
You may be aware of this, but just in case: select("date_assigned").last doesn't give you the latest date. You have to use order:
self.assignments.order(:date_assigned).last
Of course if the most recently created object is also the one with the latest date_assigned then it doesn't matter.

Change Attribute of another table

I have the table "tools" and "lend".
Im using Rails3 and when i create a lend i would like it change the attribute status of the tool to 'U'.
Would this is possible?
i tried on the model lend
after_save :change_status
def change_status
tools.update_attribute(status, 'U')
end
i tried too, on the same model:
after_save :change_status
def change_status
self.tool.update_attribute(status, 'U')
end
No success or warning on debug log.
Sugestions?
Thanks! :)
What is the relationship between lend and tool? If Lend has_many tools, you will have to do something like this:
def change_status
tools.each { |tool| tool.update_attributes(status: 'U') }
end
Note also that I am using update_attributes because update_attribute (singular) will be deprecated soon.
BTW, you should create a method in Tool to update the attribute, the Lend model should not be aware about how to set a tool as loaned. Something like
def loaned!
update_attributes status: 'U'
end
Firstly, I assume that your Lend model has_many :tools
In order to be able to do something like tool.update_attribute you'll need to work with the accepts_nested_attributes_for
Take a look at these links and they will probably set you on the right path:
RailsCasts #196 Nested Model Form Part 1
Active Record Nested Attributes
Hope this helps.

Rails 3, Model Methods / Calculated Attributes

I am dealing with numerous calculations to bring various values within a model to a simple TRUE or FALSE. Problem is, these calculations are pretty intense and not something I want to create a long, hard to follow SQL statement for. I'd rather just have the entire calculation within a method that the model could check for when returning records.
I've tried numerous ways to accomplish this, and when looking up other similar feats, others push newbs like me to SQL which might serve most purposes but will not serve mine as the calculations being done are somewhat external to the model.
Model:
class Quality < ActiveRecord::Base
...
def passed_inspection
[code that calculates based on values in model]
end
Controller:
#records = Quality.where('passed_inspection = true')
View:
Did pass inspection?: <%= record.passed_inspection %>
It sounds like the solution to your problem would be to use a Scope with a Class Method to help clean up your model. Essentially you would set up your model like this:
class Quality < ActiveRecord::Base
def self.passed_inspection
# Code that does your calculations
end
scope :passed, passed_inspection() # This needs to be below the function above
end
Then you could get this data by calling it like this
#records = Quality.passed
There is a rails cast about this problem if you need any more information: RailsCast #215 Advanced Queries
Edit: Fixed some terrible grammar

In RoR 3.0, how can you prune a table down to its 500 most recent entries?

I have a table that I'd like to keep pruned to the 500 most recent rows. What's the most efficient way to do this in rails?
One way to do it:
class MyModel
after_create do
self.class.prune(500)
end
def self.prune(max)
if count > max
order('created_at DESC').offset(max).each do |model|
model.destroy
end
end
end
end
The prune class method could also be added to ActiveRecord::Base if you want to use that on multiple models.
This is definitely one way to do it, although someone may chime in with a more efficient way. Create a method in your controller, for this example I'll call it "prune", and call it after your create action (there may be an after_filter or something similar you can use.) It should look something like this.
def prune
if MyModel.count > 500
#models = MyModel.all(:offset => 500)
#models.each do |m|
m.destroy!
end
end
end
A basic solution would be to use the following script under a scheduling application like whenever https://github.com/javan/whenever to run the following command :
Mould.order('updated_at DESC').offset(20).each {|m| m.destroy }
Substitute Mould with the name of your model. Usage of cron and scheduling has been discussed in detail in following post : A cron job for rails: best practices?