Date filter not displaying - ruby-on-rails

I created a new datetime row for a page, it works well. The column displays all the specific dates, but when I want to show specific rows using a date filter, it doesn't display a thing.
In the model:
before_validation :payment_date
def payment_date
self.payment_date = sales_order.payment_transactions.last.date
end
The date filter from the controller file:
filter :payment_date, :as => :date_range, :collection => proc { Complaint.all.map{|c| c.sales_order.try(:payment_transactions).try(:last).try(:date)} }
I suppose I did a couple of mistakes and i'm curious where the bad coding is.

In AA filtering is based on Ransack, so your filter would look as follows (assuming sales_order is an association on your model):
filter :sales_order_payment_transactions_date, label: 'Some label', as: :date_range
Here you basically go along the association chain - it is acceptable with ransack.

Related

rails simple form date input - separate integer inputs

I have a date column in my schema called dob.
I'm using a simple form to render the dob.
I want to format the input as 3 separate integer inputs.
The closest i have gotten is this code:
<%= f.input :dob, order: [:day, :month, :year] %>
However it produces this:
which is close. However i need the inputs to be integer inputs, and not dropdowns. Also i would like the month the be an integer as well.
If i use as: :integer, it just returns one single input.
Any ideas? The simple form documentation is not particularly helpful.
Thanks
you will need 3 integer inputs:
f.integer :day
f.integer :month
f.integer :year
This requires you to have day, month, and year attribute accessors on your model, and to assemble the date from the component integers, perhaps in the controller, e.g.
# users_controller.rb
def create
params[:dob] = Date.new(params[:year], params[:month], params[:day])
#... the rest of the method
end
in order to populate the integer fields for editing, you'll need methods on your model, e.g.
# in User.rb
def day
dob.day
end
# ...etc
You will also need to check that the data that the user inputs is within range.
All this special handling is why this is not normally done.

Rails: Possible to send a disabled option as a valid params value?

I have a User, and a Country models, and in User model, it has has_many :countries relationship. The country has 3 attributes -> :id, :name, :is_main
Let's say the countries table is currently populated as follow:
id name is_main
----------------------------------
1 USA true
2 Germany nil
3 France nil
4 England nil
Let's say a user is created that has countries USA, and Germany. So in this case the user.countries.pluck(:id) would return [1,2].
What I would like to achieve is that when editing the user's countries, a dropdown will appear and I am only allowed to add (or remove) countries where 'is_main' attribute is nil. In other words, in the dropdown, the USA country should either be disabled or be hidden completely to be selected. At the same time, the USA should remain in the user.countries after form submission plus any new countries that have been added from update action.
In short:
Original => user.countries.pluck(:id) => [1,2]
In edit form, if I add France to the user, the end result should be user.countries.pluck(:id) => [1,2,3]
I have tried the following:
f.collection_select(:countries, Country.where(is_main: nil), :id, :name, {}, {:multiple => true})
In doing this, the dropdown will display all the countries for me to add except for USA, which is what I desired. But the problem is when I click submit, the params[:country_ids] will be [2, 3]. As a result, after update action, the user.countries.pluck(:id) would become [2,3] instead of desired [1,2,3], effectively removing USA's id.
Is there a way to work around this? I have tried also adding :disabled option in collection_select that disables USA option, but the params[:country_ids] would still be [nil, 2, 3]. Appreciate if anyone could advise me on this.
I've come across this issue on my application. In rails 4+, set include_hidden attribute to false in multi-select selet_tags. Here's how i did it.
= f.input :countries, as: :select, collection: Country.where(is_main: nil).map{|country| [country.id, country.name]}, input_html: { multiple: true, data: { placeholder: "Countries"} }, include_hidden: false
Hope this helps you solve your issue
Actually using your example for multiple selection, your params after submit should have params[:country_ids] = [2,3]. If you are not giving the option to select USA, then it just won't be included.
You can disable options doing this:
// Your select id should be 'user_country_ids', if not change it
// This assumes that your first item will always be USA
$('#user_country_ids option:eq(0)').prop('disabled', true);
Anyway, this JS can be bypassed, so you will need to handle this on your backend too adding a validation for this in your User model:
class User
has_many :countries
validate :main_countries_always_associateds
private
def main_countries_always_associateds
errors.add(:countries, "must include main ones") if Country.where(is_main: true).any?{ |c| !self.countries.include? c }
end
end
EDIT:
If you want to always have main countries inside each user countries, then you can use before_validation callback to override this selection. I recommend to also include the disabled options on the multiple select, so the user is aware of this, the validation may become not necessary.
class User
has_many :countries
before_validation :associate_main_countries
# You should use something like this if you want your dropdown to always show marked main countries
def self.new_custom_user
User.new(countries: Country.where(is_main: true))
end
private
def associate_main_countries
Country.where(is_main: true).each do |c|
self.countries << c if !self.countries.include?(c)
end
end
end

Rails - How should mulitple checkboxes be combined as one value in a database?

As part of an application I'm building, I need to store the days on which some action needs to happen.
Currently I have this stored in a 7-digit bit-string, with each digit corresponding to one day of the week. A value of 1 for any day means the action should happen that day, a value of 0 means it should not.
Ex. String 0101110 means the action should run on Tuesday, Thursday, Friday and Saturday every week.
In my form, I have seven checkboxes set up, one for each name.
How would I go about merging these seven Boolean results into the one bitstring, such that I can save it in the database?
Would you do this in the view, or the model?
I've done some thinking myself, and one option (in the view) could be to set up a hidden field in the form that is the result of joining/concatenating the seven Booleans from the checkboxes. Then the checkboxes' values could be discarded on submit. I'm just not quite sure how to do this in rails.
Another option could be to handle the merging in the model. Again - not quite sure what to do.
Any help appreciated, thanks in advance.
Define the checkbox values for the weekdays as virtual attributes on your model, and concatenate them on a before_save hook. In your model:
attr_writer :mon, :tue, :wed, :thu, :fri, :sat, :sun
before_save :set_weekdays
private
def set_weekdays
self.weekdays = bitstr(#mon) + bitstr(#tue) + bitstr(#wed) # etc
end
def bitstr(bool)
bool ? "1" : "0"
end
Make sure to permit mon and co as strong parameters for the model in Rails 4. You might also want to define getters for these attributes that would get filled from the bitstring, so that the form could render with the correct checkboxes pre-selected on edits.
I am assuming the week column is week
You can make the week column of type: text and add this to your model
serialize :week : this helps to save an array in the column
next, create a class Week, where week.rb:
class Week
include ActiveModel::Model
attr_accessor :id, :name
DAYS = [
{id: 1, "day" => "monday"},
{id: 2, "day" => "tuesday"},
...
]
def self.days
DAYS.map {|d| self.new(
id: d[:id],
name: d[:day]
)}
end
end
and then, you can call the checkboxes from the view as follow:
<%= f.collection_check_boxes(:week, Week.days, :id, :name, include_hidden: false) do |b| %>
<%= b.check_box(class: "check_box") %> <%= b.object.name %>
<% end %>
lastly, dont forget to make the week atribute accesible from the controller. In rails 4, this will be:
params.require(:user).permit(week: [])
Hope this helps you?

mongoid batch update

I'd like to update a massive set of document on an hourly basis.
Here's the
fairly simple Model:
class Article
include Mongoid::Document
field :article_nr, :type => Integer
field :vendor_nr, :type => Integer
field :description, :type => String
field :ean
field :stock
field :ordered
field :eta
so every hour i get a fresh stock list, where :stock,:ordered and :eta "might" have changed
and i need to update them all.
Edit:
the stocklist contains just
:article_nr, :stock, :ordered, :eta
wich i parse to a hash
In SQL i would have taken the route to foreign keying the article_nr to a "stock" table, dropping the whole stock table, and running a "collection.insert" or something alike
But that approach seems not to work with mongoid.
Any hints? i can't get my head around collection.update
and changing the foreign key on belongs_to and has_one seems not to work
(tried it, but then Article.first.stock was nil)
But there has to be a faster way than iterating over the stocklist array of hashes and doing
something like
Article.where( :article_nr => stocklist['article_nr']).update( stock: stocklist['stock'], eta: stocklist['eta'],orderd: stocklist['ordered'])
UPDATING
You can atomically update multiple documents in the database via a criteria using Criteria#update_all. This will perform an atomic $set on all the attributes passed to the method.
# Update all people with last name Oldman with new first name.
Person.where(last_name: "Oldman").update_all(
first_name: "Pappa Gary"
)
Now I can understood a bit more. You can try to do something like that, assuming that your article nr is uniq.
class Article
include Mongoid::Document
field :article_nr
field :name
key :article_nr
has_many :stocks
end
class Stock
include Mongoid::Document
field :article_id
field :eta
field :ordered
belongs_to :article
end
Then you when you create stock:
Stock.create(:article_id => "123", :eta => "200")
Then it will automaticly get assign to article with article_nr => "123"
So you can always call last stock.
my_article.stocks.last
If you want to more precise you add field :article_nr in Stock, and then :after_save make new_stock.article_id = new_stock.article_nr
This way you don't have to do any updates, just create new stocks and they always will be put to correct Article on insert and you be able to get latest one.
If you can extract just the stock information into a separate collection (perhaps with a has_one relationship in your Article), then you can use mongoimport with the --upsertFields option, using article_nr as your upsertField. See http://www.mongodb.org/display/DOCS/Import+Export+Tools.

Querying embedded objects in Mongoid/rails 3 ("Lower than", Min operators and sorting)

I am using rails 3 with mongoid.
I have a collection of Stocks with an embedded collection of Prices :
class Stock
include Mongoid::Document
field :name, :type => String
field :code, :type => Integer
embeds_many :prices
class Price
include Mongoid::Document
field :date, :type => DateTime
field :value, :type => Float
embedded_in :stock, :inverse_of => :prices
I would like to get the stocks whose the minimum price since a given date is lower than a given price p, and then be able to sort the prices for each stock.
But it looks like Mongodb does not allow to do it.
Because this will not work:
#stocks = Stock.Where(:prices.value.lt => p)
Also, it seems that mongoDB can not sort embedded objects.
So, is there an alternative in order to accomplish this task ?
Maybe i should put everything in one collection so that i could easily run the following query:
#stocks = Stock.Where(:prices.lt => p)
But i really want to get results grouped by stock names after my query (distinct stocks with an array of ordered prices for example). I have heard about map/reduce with the group function but i am not sure how to use it correctly with Mongoid.
http://www.mongodb.org/display/DOCS/Aggregation
The equivalent in SQL would be something like this:
SELECT name, code, min(price) from Stock WHERE price<p GROUP BY name, code
Thanks for your help.
MongoDB / Mongoid do allow you to do this. Your example will work, the syntax is just incorrect.
#stocks = Stock.Where(:prices.value.lt => p) #does not work
#stocks = Stock.where('prices.value' => {'$lt' => p}) #this should work
And, it's still chainable so you can order by name as well:
#stocks = Stock.where('prices.value' => {'$lt' => p}).asc(:name)
Hope this helps.
I've had a similar problem... here's what I suggest:
scope :price_min, lambda { |price_min| price_min.nil? ? {} : where("price.value" => { '$lte' => price_min.to_f }) }
Place this scope in the parent model. This will enable you to make queries like:
Stock.price_min(1000).count
Note that my scope only works when you actually insert some data there. This is very handy if you're building complex queries with Mongoid.
Good luck!
Very best,
Ruy
MongoDB does allow querying of embedded documents, http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-ValueinanEmbeddedObject
What you're missing is a scope on the Price model, something like this:
scope :greater_than, lambda {|value| { :where => {:value.gt => value} } }
This will let you pass in any value you want and return a Mongoid collection of prices with the value greater than what you passed in. It'll be an unsorted collection, so you'll have to sort it in Ruby.
prices.sort {|a,b| a.value <=> b.value}.each {|price| puts price.value}
Mongoid does have a map_reduce method to which you pass two string variables containing the Javascript functions to execute map/reduce, and this would probably be the best way of doing what you need, but the code above will work for now.

Resources