Trying to check to see if two params are in an id field for an if statement in my rails app.
For example i want to state if both [params[:one], params[:two]] exist in column :item_id then continue, if not, don't include in results.
So in my example below it would only chose item_id one as both one and two params exist in the item_id.
Table
item_id | one | two
1 | 2300 | 2255
1 | 2000 | 2304
2 | 2300 | 2000
3 | 2255 | 2222
View Form code
<%= form_tag vpc_search_path do %>
<%= select_tag :one, options_from_collection_for_select(#variety, "variety_id", "variety_name", :selected => "2300"), include_blank: false %>
<%= select_tag :two, options_from_collection_for_select(#variety, "variety_id", "variety_name", :selected => "2255"), include_blank: false %>
<%= submit_tag "Compare" %>
<% end %>
Controller code
if Result.where(trial_id: [params[:one], params[:two]])
#comparison = Result.where('variety_id' => [params[:one], params[:two]], 'year' => params[:year])
else
redirect_to vpc_index_url, notice: "error."
end
probably you should move this check in model
if self.where(item_id: [params[:one] && params[:two]]).present?
then do this
else
do this
end
or probably if you can provide params hash structure I can improve my answer
I'm not sure if I understand that right, but try this:
if SomeModel.where(item_id: [params[:one],params[:two]]).count == 2
#params :one and :two are on the item_id column
else
#one or both are not on the item_id column
end
please explain your problem better, it's hard to understand
Further to the two answers which I upvoted already, you may want to consider this:
You'd use the where function to create the logic, but you need to consider how you're going to call this. Here's how I would do it:
Custom Validator
Might be a bit long-winded, but you may be able to create a custom validator, which you'll be able to call to determine if the params exist in the db:
class TableValidator < ActiveModel::Validator
def validate(record)
unless self.where(item_id: [record.one && record.two]).present?
record.errors[:name] << 'Need a name starting with X please!'
end
end
end
class Table
include ActiveModel::Validations
validates_with TableValidator
end
I used Magnum's code for the logic & the Rails guide for the custom validator
This probably won't work out of the box, but it's what I would look at
Related
I'm following this tutorial to implement a filtering feature in my Rails app. I want admins to be able to filter by age, identifier, and a date interval the users were created. It is the last bit that is causing me some headache.
In my model user.rb, I have defined the following scopes:
scope :created_between, -> (startdate, enddate) {where(created_at: startdate..enddate)}
scope :identified, -> { where.not(identifier: [nil, '']) }
scope :age, -> (age) { where("age > ?", age)}
In my controller users_controller.rb, I use a function to filter the params:
def search
filter = params.slice(:age, :created_between, :identified)
filter.each do |key, value|
if value.present?
#users = #users.public_send(key,value)
else
#users = #users.public_send(key)
end
end
end
I differentiate between a value present or not, since the :identified scope is implemented as a checkbox and therefore passes no value like
Lastly, I have created a form for all the possible filters like so, in my view.html.erb file:
<%= form_tag users_search_path, :method => :get, :enforce_utf8 => false do %>
<%= date_field :created_between, "from" %>
<%= date_field :created_between, "to" %>
<%= check_box_tag :identified, '', false %>
<%= text_field_tag :age, "age" %>
<% end %>
The filter for age and identified works. When I submit the form the query becomes /users/search?identified=&created_between[from]=&created_between[to]= when I only check the checkbox identified (the date_field is also passed although I did not submit any date). And /users/search?age=21&created_between[from]=&created_between[to]= when I only submit an age.
My problem is that whenever I try to submit two dates for the created_between scope I get an wrong number of arguments (1 given, expected 2) error. I'm not sure that I'm submitting the date fiels correctly.
How can I pass the two needed params to the scope? Or should I do it another way instead?
Sometimes just writing out the question seems to make things clearer. However, the solution was to alter my scope function for :created_between to:
scope :created_between, -> (date) {where(created_at: date[:from]..date[:to])}
We're using the "serialize" feature of ActiveRecord in Rails like this:
class User < ActiveRecord::Base
serialize :favorite_colors, Array
....
end
So we can have
u = User.last
u.favorite_colors = [ 'blue', 'red', 'grey' ]
u.save!
So basically ActiveRecord is serializing the array above and stores it in one database field called favorite_colors.
My question is: How do you allow a user to enter his favorite colors in a form?
Do you use a series of textfields? And once they're entered, how do you show them in a form for him to edit?
This is a question related to Rails Form Helpers for serialized array attribute.
Thanks
If you want multi-select HTML field, try:
= form_for #user do |f|
= f.select :favorite_colors, %w[full colors list], {}, :multiple => true
If you're using simple_form gem, you can present the options as check boxes easily:
= simple_form_for #user do |f|
= f.input :favorite_colors, as: :check_boxes, collection: %w[full colors list]
I have solved this problem by 'flattening' the array in the view and
reconstituting the array in the controller.
Some changes are needed in the model too, see below.
class User < ActiveRecord::Base
serialize :favorite_colors, Array
def self.create_virtual_attributes (*args)
args.each do |method_name|
10.times do |key|
define_method "#{method_name}_#{key}" do
end
define_method "#{method_name}_#{key}=" do
end
end
end
end
create_virtual_attributes :favorite_colors
end
If you don't define methods like the above, Rails would complain about the form element's
names in the view, such as "favorite_colors_0" (see below).
In the view, I dynamically create 10 text fields, favorite_colors_0, favorite_colors_1, etc.
<% 10.times do |key| %>
<%= form.label :favorite_color %>
<%= form.text_field "favorite_colors_#{key}", :value => #user.favorite_colors[key] %>
<% end %>
In the controller, I have to merge the favorite_colors_* text fields into an array BEFORE calling
save or update_attributes:
unless params[:user].select{|k,v| k =~ /^favorite_colors_/}.empty?
params[:user][:favorite_colors] = params[:user].select{|k,v| k =~ /^favorite_colors_/}.values.reject{|v| v.empty?}
params[:user].reject! {|k,v| k=~ /^favorite_colors_/}
end
One thing I'm doing is to hard-code 10, which limits how many elements you can have in the favorite_colors array. In the form, it also outputs 10 text fields. We can change 10 to 100 easily. But we will still have a limit. Your suggestion on how to remove this limit is welcome.
Hope you find this post useful.
To allow access to AR attributes, you have to grant them like this:
class User < ActiveRecord::Base
serialize :favorite_colors, Array
attr_accessible :favorite_colors
....
end
I've built a lookup table in my Rails application.
It is a table that stores lookup text values for drop-down pickers or possibly check boxes. I want the lookup table to have a view associated so the values can be easily edited. I also may want to share lookup values among multiple models for a single field in the future.
So far I've managed to get it to work for the selection of values, but then displaying the text value again on a show or index view has been problematic.
This is how I built the lookup table
rails g scaffold Lookup field_name lookup_text table_name note
In the edit.html.erb where there is a lookup on a field, I've got code like this, which works and allows me to pick from a list.
<div class="field">
<%= f.label :status %><br />
<%= f.collection_select :status, Lookup.find(:all,:conditions => ["table_name = 'course' and field_name = 'status'"]), :id, :lookup_text, include_blank: true,:prompt => "Status" %>
</div>
That all works fine. When I try to display it back I cannot find the correct syntax. The best I have found is this:
(in the controller)
#status = Lookup.where(:id => #course.status).pluck(:lookup_text)
(in the view)
<p>
<b>Status:</b>
<%= #status %>
</p>
I think I am getting the entire object. It displays like this:
Status: ["Active"]
My questions are:
(1) How do I display the value only?
(2) Is this the best approach?
I've had a look at these and other SO questions, but none are really what I am looking for:
Rails Polymorphic with Lookup Table
Implementing a lookup table in Rails
EDIT
OK this works, but it doesn't look like it is the correct solution. Has anyone got a better way of doing this?
#status = Lookup.where(:id => #course.status).pluck(:lookup_text)[0]
Just another way to show the value is #status = Lookup.find(#course.status).lookup_text
Why not to try use classes for different lookups:
class CourseStatus < ActiveRecord::Base
set_table_name "lookups"
default_scope where("table_name = 'course' and field_name = 'status'")
end
class Course
belongs_to :course_status
end
You then can use:
CourseStatus.all # e.g. to fill select options
Course.first.course_status.lookup_text # => "Active" or smth else
Or without classes:
class Lookup
def self._by_table_and_field(table, field)
['table_name = ? and field_name = ?', table, field]
end
scope :by_table_and_field, lambda { |table, field|
where(Lookup._by_table_and_field(table, field))
}
end
class Course
belongs_to :status, class_name: 'Lookup', conditions: Lookup._by_table_and_field('course', 'status')
end
Lookup.by_table_and_field('course', 'status').all
Course.first.status.lookup_text
I'm using a select field in a Rails app that is NOT tied to a related model, but stores integer values for a static series of options , i.e.,
<%= select (:this_model, :this_field, [['Option1',1],['Option2',2],['Option3',3],['Option4',4]] ) %>
In a show/ index view, if I want to display the option text (i.e. Option1, Option2, etc) rather than the integer value stored in the database, how do I achieve this?
Thanks for helping a noob learn the ropes!
EDIT
Based on Thorsten's suggestion below, I implemented the following. But it is returning nil, and I can't figure out why.
Invoice model:
##payment_status_data = { 1 => "Pending Invoice" , 2 => "Invoiced" , 3 => "Deposit Received", 4 => "Paid in Full"}
def text_for_payment_status
##payment_status_data[payment_status]
end
Invoice show view:
Payment Status: <%= #invoice.text_for_payment_status %>
In the console:
irb > i=Invoice.find(4)
=> [#<Invoice id: 4, payment_status: 1 >]
irb > i.text_for_payment_status
=> nil
I've tried defining the hash with and without quotes around the keys. What am I missing?
something like this would work:
<%= form_for #my_model_object do |form| %>
<%= form.label :column_name "Some Description" %>
<%= form.select :field_that_stores_id, options_for_select({"text1" => "key1", "text 2" => "key2"}) %>
<% end %>
Update
If you later want to display the text you can get it from a simple hash like this:
{"key1" => "text 1", "key2" => "text2"}[#my_object.field_that_stores_id]
But you better store this hash somewhere in a central place like the model.
class MyModel < ActiveRecord
##my_select_something_data = {"key1" => "text 1", "key2" => "text2"}
def text_for_something_selectable
##my_select_something_data[field_that_stores_id]
end
end
Then you can use it in your views like
#my_object.text_for_something_selectable
There are many possible variations of this. But this should work and you would have all information in a central place.
Update
Ok, I used something similar for our website. We need to store return_headers for rma. Those need to store a return reason as a code. Those codes are defined in an external MS SQL Server Database (with which the website exchanges lots of data, like orders, products, and much more). In the external db table are much more return reasons stored than I actually need, so I just took out a few of them. Still must make sure, the codes are correct.
So here goes he model:
class ReturnHeader < AciveRecord::Base
##return_reason_keys = {"010" => "Wrong Produc",
"DAM" => "Damaged",
"AMT" => "Wrong Amount"}
def self.return_reason_select
##return_reason_keys.invert
end
def return_reason
##return_reason_keys[nav_return_reason_code]
end
end
Model contains more code of course, but that's the part that matters. Relevant here is, that keys in the hash are strings, not symbols.
In the views i use it like this:
In the form for edit:
<%= form_for #return_header do |form| %>
<%= form.label :nav_return_reason_code "Return Reason" %>
<%= form.select :nav_return_reason_code, options_for_select(ReturnHeader.return_reason_select, #return_header.nav_return_reason_code) %>
<% end %>
(Maybe no the most elegant way to do it, but works. Don't know, why options_for_select expects a hash to be "text" => "key", but that's the reason, why above class level method returns the hash inverted.)
In my index action the return reason is listed in one of the columns. There I can get the value simply by
#return_headers.each do |rh|
rh.return_reason
end
If you have trouble to get it run, check that keys a correct type and value. Maybe add some debug info with logger.info in the methods to see what actual data is used there.
I'm trying put an if statement directly into a select field in rails, with no success.
Here is what I've tried:
<%= f.select (:book_id,{
if #a!=1
"Harry Potter", 1,
end
if #b!=2
"Lord of the Rings", 2,
end
end %>`
Any ideas?
Don't do this. It's ugly, and not fun for you to maintain. Also, no good trying to put if-statements or anything other than hash values inside a hash declaration. How about a helper?
Helper code (untested):
def book_select(f)
options = {}
options['Harry Potter'] = 1 unless #a == 1
options['Lord of the Rings'] = 2 unless #b == 2
f.select :book_id, options
end
View code:
<%= book_select(f) %>