Select certain record within response from ActiveRecord - ruby-on-rails

I have a call to ActiveRecord in my controller as so:
#configurations = EmailConfiguration.where(customer_id: '1', email_template: '1')
This will return all EmailConfigurations that have the correct parameters. Each record has a field_id and a the_value. I want to display the value in the view:
#configurations.where(field_id: 1).the_value
What do I need to add to the view to select a certain record within the collection that is returned by the database?

You can use select for a quick filter on arrays
#configurations.select {|c| c.field_id == 1}
that will return all collections with field_id = 1. If you know there is only one, you could chain it for a direct output:
#configurations.select {|c| c.field_id == 1}.first.the_value

#configurations.where(field_id: 1)
returns a collection of objects(array) even if there is only one result. If you would like to show only one you can do as suggested above:
#configurations.select {|c| c.field_id == 1}.first.the_value
If you want to show all of the "the_values" you can do
field_1_configs = #configurations.select do |c| c.field_id == 1
end
field_1_configs.map{|config| config.the_value }

Related

ActiveRecord next item

I am currently getting back a list of items in a prioritized order:
#priotizedorder = #categories.order(:priority)
What I want to create is a button that allows a user to get to the next category from an item. I'm trying to do that by saying:
#activecategory = #categories.where(:name => params[:cat]).first
#nextcategory = #priotizedorder.select {|item|'name' == #activecategory}
But that's returning an empty array:
[]
How do I select the next category in an active record?
Firstly, your question is not clear to me, you are asking for next category but you are searching the given category in the order, according to my knowledge I am providing the solution
Your statement must be
#nextcategory = #priotizedorder.select {|item| item == #activecategory}
When you are using 'select', above statement returns an array of results matching with the value, you should take the first value from the array.
i.e., #nextcategory = #priotizedorder.select {|item| item == #activecategory}.first
(OR) You can use find method
#nextcategory = #priotizedorder.find {|item| item == #activecategory}
If you want to select the next prioritised category of given item, then use the below code
#currentcategory = #priotizedorder.find {|item| item == #activecategory}
#currentcategory_index = #priotizedorder.index(#currentcategory)
#nextcategory = #priotizedorder[#currentcategory_index+1]

Relation passed to #or must be structurally compatible. Incompatible values: [:references]

I have two queries, I need an or between them, i.e. I want results that are returned by either the first or the second query.
First query is a simple where() which gets all available items.
#items = #items.where(available: true)
Second includes a join() and gives the current user's items.
#items =
#items
.joins(:orders)
.where(orders: { user_id: current_user.id})
I tried to combine these with Rails' or() method in various forms, including:
#items =
#items
.joins(:orders)
.where(orders: { user_id: current_user.id})
.or(
#items
.joins(:orders)
.where(available: true)
)
But I keep running into this error and I'm not sure how to fix it.
Relation passed to #or must be structurally compatible. Incompatible values: [:references]
There is a known issue about it on Github.
According to this comment you might want to override the structurally_incompatible_values_for_or to overcome the issue:
def structurally_incompatible_values_for_or(other)
Relation::SINGLE_VALUE_METHODS.reject { |m| send("#{m}_value") == other.send("#{m}_value") } +
(Relation::MULTI_VALUE_METHODS - [:eager_load, :references, :extending]).reject { |m| send("#{m}_values") == other.send("#{m}_values") } +
(Relation::CLAUSE_METHODS - [:having, :where]).reject { |m| send("#{m}_clause") == other.send("#{m}_clause") }
end
Also there is always an option to use SQL:
#items
.joins(:orders)
.where("orders.user_id = ? OR items.available = true", current_user.id)
You can write the query in this good old way to avoid error
#items = #items.joins(:orders).where("items.available = ? OR orders.user_id = ?", true, current_user.id)
Hope that helps!
Hacky workaround: do all your .joins after the .or. This hides the offending .joins from the checker. That is, convert the code in the original question to...
#items =
#items
.where(orders: { user_id: current_user.id})
.or(
#items
.where(available: true)
)
.joins(:orders) # sneaky, but works! 😈
More generally, the following two lines will both fail
A.joins(:b).where(bs: b_query).or(A.where(query)) # error! 😞
A.where(query).or(A.joins(:b).where(bs: b_query)) # error! 😞
but rearrange as follows, and you can evade the checker:
A.where(query).or(A.where(bs: b_query)).joins(:b) # works 😈
This works because all the checking happens inside the .or() method. It's blissfully unaware of shennanigans on its downstream results.
One downside of course is it doesn't read as nicely.
I ran into the same issue, however the code was defined in a different place and was very difficult to change directly.
# I can't change "p"
p = Post.where('1 = 1').distinct # this could also be a join
And I needed to add an or statement to it
p.or(Post.where('2 = 2'))
The following code won't raise an error, because it has distinct like the initial relationship.
p.or(Post.where('2 = 2').distinct)
The problem with it it that it only works as long as you know the relationship. It may or not have a join, or distinct.
This works regardless of what the relationship is:
p.or(p.unscope(:where).where('2 = 2'))
=> SELECT DISTINCT `posts`.* FROM `posts` WHERE ((1 = 1) OR (2 = 2))
It occurs when you try to combine two multi-active records of the same type, but one of them has a joins value or an includes value, or in your case a reference value, that the other does not.
Therefore we need to match the values between them, and I found a general way to do this without knowing the actual values in advance.
items_1 = #items.joins(:orders)
.where(orders: { user_id: current_user.id})
items_2 = #items.where(available: true)
.joins(items_1.joins_values)
.includes(items_1.includes_values)
.references(items_1.references_values)
#items = items_1.or(items_2)
just solve it!
def exec_or_statement(q1, q2)
klass = q1.klass
key = klass.primary_key
query_wrapper_1 = {}
query_wrapper_1[key] = q1
query_wrapper_2 = {}
query_wrapper_2[key] = q2
klass.where(query_wrapper_1).or(klass.where(query_wrapper_2))
end
query_1 = #items.where(available: true)
query_2 =
#items
.joins(:orders)
.where(orders: { user_id: current_user.id})
exec_or_statement(query_1, query_2)

How to modify an attribute of a certain item in a model

I have a model called Category which contains categories that are used to categorise products. One of the categories is called Experiences. On a specific query, I'd like to modify it from Experiences to Experiences * for display purposes.
I have tried to do this via a map, but am getting a blank value for Experiences.
This is my code:
def self.with_exp_star
Category.all.map { |element|
if element.name == "Experiences"
element.name = "Experiences *"
else
element
end
}
end
Any ideas?
Well, when element.name == "Experiences" you are pushing element.name to the result array, but element object otherwise, while you should return element in both ways:
Category.all.map { |element|
element.name += ' *' if element.name == 'Experiences'
element
}
If you're using rails 3 upwards you can chain a query with update_all, like so:
Categories.where(:name => "Experiences).update_all(:name => "Experiences *")

Put specific collection/array item on the last position in rails

I have a collection/array in rails, transformed to json it looks like this:
#collection = [{"order_number":"123","item":"Paper"},{"order_number":"567","item":"Ruler"},{"order_number":"344","item":"Pen"},{"order_number":"342","item":"Pencil"},{"order_number":"877","item":"Keyboard"}]
I would like to pick the item with the order_number "342" and put it at the last position of the collection, so the new collection looks like this:
#collection = [{"order_number":"123","item":"Paper"},{"order_number":"567","item":"Ruler"},{"order_number":"344","item":"Pen"},{"order_number":"877","item":"Keyboard"},{"order_number":"342","item":"Pencil"}]
In theory, it would look like this:
#collection.last = #collection[3]
but that is obviously not fancy ruby style nor would it re-sort the array as in my example.
Also I don't know the index of the item as it can change depending on what the user shops.
how about:
#collection << #collection.delete_at[#collection.index{|x| x[:order_number] == "342"}]
This basically searches the index of element with :order_number 342 first, uses that index to delete it, and then store the deleted element at the end again.
You can also use the partition method:
#collection = #collection.partition { |h| h['order_number'] != '342' }.flatten
Just split your collection on two (without 342 order and with 342 order), then just join them. It should looks like:
#collection = #collection.select {|e| e[:order_number] != '342' } + #collection.select {|e| e[:order_number] == '342' }
If you have an index of an item it boils down to
#collection << #collection.delete_at(3)
If you don't, you could try finding it using
#collection.find_index{ |el| el["order_number"] == "123" }
Alternative you can try this too:
> #collection.each_with_index{ |key,value| #collection.push(#collection.delete_at(value)) if key[:order_number] == "344" }
#=>[{:order_number=>"123", :item=>"Paper"}, {:order_number=>"567", :item=>"Ruler"}, {:order_number=>"342", :item=>"Pencil"}, {:order_number=>"877", :item=>"Keyboard"}, {:order_number=>"344", :item=>"Pen"}]

retrieve data from database - hash

I have a table called audits which has a column 'changes' storing data in the form of hash
I would like to retrieve all entries with the following conditions:
- auditable_type = 'Expression'
- action = 'destroy'
- changes = { :EXP_SUBMISSION_FK =>'9999992642'}
I first tried the following code which returns me with nothing:
#deleted_history = Audit.find(:all, :conditions => ["auditable_type =? AND action = ? AND changes = ?",'Expression', 'destroy' , { :EXP_SUBMISSION_FK =>'9999992642'} ])
I then tried the following code which retrieves all entries in the 'audits' table with auditable_type = 'Expression' and action = 'destroy'.
I then loop through the resultset and discards all entries where EXP_SUBMISSION_FK is not equal to 9999992642. The code below returns me 5 entries/records
#deleted_history = Audit.find(:all, :conditions => ["auditable_type =? AND action = ?",'Expression', 'destroy' ])
#deleted_history.each do |test|
if test.changes['EXP_SUBMISSION_FK'] != 9999992642
#deleted_history = #deleted_history.reject { test }
end
end
I would like to know where did I go wrong with the first code example and whether there is a way of retrieving all entries with the aforementioned conditions in a much simpler way.
Thanks a lot for your help.
i'd do:
#deleted_history.select!{|hist| hist.changes['EXP_SUBMISSION_FK'] == '9999992642'}
One potential cause of failure is that you're looking for 9999992642 but you state before the value is '9999992642'
You just use something like below. I am storing element_values as a hash and i am selecting records based on the key/value pair.
scope :find_by_field_values, lambda {
|field_name, field_value|
(where("element_values like ?", "%\"#{field_name}\":\"%#{field_value}%"))
}
just try this based on your scenario.

Resources