I want to extract the id number of a unique record, that resides in a different controller as an integer, so I can save it as part of a new record in a new controller.
I can't seem to get the id to shed it's 'Array' attribute.
I've been using this:
class MessagesController < ApplicationController
def incoming
a = Group.where("name = ?", name).map { |n| n.id }
group_number = a.id
puts "#{group_number} is the number!"
end
output is always [2] or [3] or whatever.
adding this doesn't seem to cure it
group_as_int = group_number.to_i
Lastly, the reason I'm doing all this is to save that group number as a new record in a third controller, like this:
Subscriber.create(:group_id => group_number, :active => "1")
or
Subscriber.create(:group_id => group_as_int, :active => "1")
Of course, the create balks when I try to pass an array into the create function.
Thoughts?
You are trying to put business logic into the controller.
Try to refactor your methods and put them into your models instead.
Beside that you get the number in the following way:
group = Group.where("name = ?", name).first
group_number = group.id if group.present?
You might want to try .first to get the integer out of the array.
I will try to explain from your code what you did wrong.
The first line:
matching_group_ids = Group.where("name = ?", name).map { |n| n.id }
You called it a, but i prefer more verbose names. matching_group_ids now holds an array of id's. To get the first value of this array, the easiest solution is to just write
group_number = matching_group_ids[0]
or, more readable:
group_number = matching_group_ids.first
Mind you: you should test that the returned array is not empty.
Hope this helps.
Related
This is a custom rake task file, if that makes a difference.
I want to pull all user_id's from Pupil, and apply them to get the User.id for all pupils.
It happily prints out line 2 with correct user_id, but then considers user_id a 'method' and breaks on line 3. Why? Where is my mistake?
course_pupils = Pupil.where(course_id: study.course_id)
course_pupils.map { |a| puts a.user_id }
pupils = User.where(id: course_pupils.user_id )
course_pupils is still a relation when you are calling it in line 3. Line 2 is non destructive (and if it was, it would turn it into an array of nils because puts returns nil).
You need to do:
pupils = User.where(id: course_pupils.pluck(:user_id) )
Or something like that
You are doing it wrong, you cannot call an instance method user_id on a collection, try this instead
user_ids = Pupil.where(course_id: study.course_id).pluck(:user_id)
pupils = User.where(id: user_ids )
Hope that helps!
I want to call the ActiveRecord method where with an array for a column. If the each item on the array doesn't exist, create the object. The closest method I found for this is first_or_create but this seems to be called only once, not for each time the record doesn't exist. Below is my example code-
hashtag_list = params[:message][:hashtag_primary]
#hashtags = Hashtag.where({:name => hashtag_list}).first_or_create do |hashtag|
hashtag.creator = current_user.id
end
Rails version- 4.2.1
I don't know a direct method, only a workaround
existing_tags = Hashtag.where({:name => hashtag_list}).pluck(:name)
not_existing_tags = hashtag_list - existing_tags
#hashtags = Hashtag.where({:name => existing_tags}).all
not_existing_tags.each do |tag|
#hashtags << Hashtag.new name: tag
end
#hashtags.each do |hashtag|
hashtag.creator = current_user.id
end
This is expected behavior of where + first_or_create method. Basically where(field: array) produces an SQL to find all records where field matches any item in the array. Than you have first_or_create method which takes the first record from results or creates a new one with escaped array value assigned to a field (so something like field: "[\"foo\", \"bar\"]" when used as where(field: %w(foo bar)).
If you want to create records for each hashtag from your list, you should iterate over it:
if #hashtag = Hashtag.where({:name => hashtag_list}).first
# do something if found the first one
else
hashtag_list.each do |hashtag|
# create an object
end
end
If you want to create missing hashtags even if the record is found, you can extract this to a private helper method with missing tags as the argument and re-write code as:
if #hashtags = Hashtag.where({:name => hashtag_list})
# do something if found
end
create_missing_hashtags(hashtag_list - #hashtags.pluck(:name))
The model User has first, last and login as attributes. It also has a method called name that joins first and last.
What I want is to iterate through the Users records and create an array of hashes with the attributes I want. Like so:
results = []
User.all.map do |user|
record = {}
record["login"] = user.login
record["name"] = user.name
results << record
end
Is there a cleaner way in Ruby to do this?
Trying to map over User.all is going to cause performance issues (later, if not now). To avoid instantiating all User objects, you can use pluck to get the data directly out of the DB and then map it.
results = User.all.pluck(:login, :first, :last).map do |login, first, last|
{ 'login' => login, 'name' => first << last }
end
Instantiating all the users is going to be problematic. Even the as_json relation method is going to do that. It may even be a problem using this method, depending on how many users there are.
Also, this assumes that User#name really just does first + last. If it's different, you can change the logic in the block.
You can use ActiveRecord::QueryMethods#select and ActiveRecord::Relation#as_json:
User.select(:login, '(first || last) as name').as_json(except: :id)
I would write:
results = User.all.map { |u| { login: u.login, name: u.name } }
The poorly named and poorly documented method ActiveRecord::Result#to_hash does what you want, I think.
User.select(:login, :name).to_hash
Poorly named because it does in fact return an array of Hash, which seems pretty poor form for a method named to_hash.
I have a form being submitted that is saving multiple records, and the parameters look something like this:
{
"utf8"=>"✓",
"_method"=>"put",
"products"=> {
"321" => {
"sale_price"=>"10"
},
"104" => {
"sale_price"=>"10"
}
}
}
Then in my controller, I have this:
#updated_products = Product.update(params[:products].keys, params[:products].values)
This expects the keys (321, 104) to be IDs.
However, I'm using the to_param in my model to change my urls from IDs to another column value.
Is there a way to take the params[:products].keys and swap them for the appropriate IDs so I can use IDs in the .update() statement.
I can use Product.find_by_column_name(321).id to get the id although I don't know how to do this. Still new to rails.
Any help would be appreciated. Thanks.
Looking at the source code here #update iterates through each key and runs update_attributes so it goes through all the validations. You can change your method to
#updated_products = params[:products].inject([]) do |array, (column_id, attributes)|
product = Product.find_by_column_id column_id
if product.update_attributes(attributes)
array << product
else
array
end
end
This may seem a little complex but it is equal to this one below which is easier to understand and code read
#updated_products = []
params[:products].each do |column_id, attributes|
product = Product.find_by_column_id column_id
if product.update_attributes(attributes)
#updated_products << product
end
end
In SQL I would do this:
SELECT minimummonths WHERE name = "gold"
I want to do the same in Ruby on Rails and have the following in the new section of my orders controller:
#plan = params[:plan]
#Payplanrow = Payplan.where(:name => #plan).minimummonths
I then try to display #payplanrow in my page using <%=#Payplanrow %> but it doesnt work. I get the error:
undefined method `minimummonths' for #<ActiveRecord::Relation:0x007fe30f870ec0>
I want to print the minimummonths value for the plan selected. There will only ever be one row of data corresponding to the #plan value.
I'm pretty new to Ruby on Rails so I'm just trying to get a pointer in the right direction. I looked everywhere but there doesn't seem to be an example of this.
The problem is Payplan.where(:name => #plan) is returning an array of Payplan objects. Assuming you are using Rails 3, you can read more about it in "Active Record Query Interface".
But, if you are certain that your query is returning only one record you could do:
#Payplanrow = Payplan.where(:name => #plan).first.try(:minimummonths)
The Rails way is to have a scope in your model:
class Payplan < ActiveRecord::Base
scope :by_name, lambda {|name|
{:conditions => {:name => name}}
}
end
#controller
#Payplanrow = Payplan.by_name(#plan).first.try(:minimummonths)
Although it's not really optimal, you can do:
#Payplanrow = Payplan.where(:name => #plan).first.minimummonths
You can use pluck to get only the minimummonths value :
minimummonths = Payplan.where(:name => #plan).pluck(:minimummonths).first
Instead of using where then first, it's better to use find when you are expecting a single record.
#Payplanrow = Payplan.find_by_name(#plan).try(:minimummonths)
That should be:
Payplan.where(:name => #plan).first.minimummonths