Trying to mirror my API responses with as little code duplication as possible and have this so far....
Really, this is a "There has to be a better 'Rails way' to accomplish this..." question.
class Quote < ActiveRecord::Base
belongs_to :author
has_many :votes
def as_json(options={})
hash = super(except)
hash[:author] = self.author.name
hash[:vote_count] = self.votes.count
hash
end
def to_xml(options={})
hash = super(except)
hash[:author] = self.author.name // <---- line 14
hash[:vote_count] = self.votes.count
hash
end
private
def except
{ :except => [ :id, :created_at, :updated_at, :author_id ] }
end
end
JSON response works like a champ, but the xml throws this error
can't convert Symbol into Integer
app/models/quote.rb:14:in `[]='
app/models/quote.rb:14:in `to_xml'
As a secondary question, is the the best way to customize the output like I am? I'd like to not duplicate this logic if I can avoid it.
hash[:author] = self.author.name
hash[:vote_count] = self.votes.count
hash
to_xml returns an XML string, not a hash. That's why it's surprised by a symbol in the brackets: it thinks you're trying to modify a particular character, e.g. name[0] = 'A'
If you're interested in changing bits of the XML output, maybe you should just build a new hash of the attributes you want and run to_xml on that.
Related
In my model I have results
store_accessor :results
and in controller its like
if current_user.test
#results = current_user.test.results
end
And I am printing this value at the front end it keeps showing 0
def update
stats = user.test
stats.data_will_change!
attributes = { results: "#{(stats.results.to_i) + 1}" }
stats.update_attributes(attributes)
end
It's going through the function but the value at the front-end is still 0
store_accessor requires at least two attributes
store_accessor :column_name, :attribute
:column_name column is presumed to be Hash like type eg Hstore in PostgreSQL or json or something like that.
:attribute than behaves like standard database column in ActiveRecord model.
You can then call something like:
model.attribute = 5
model.save
It also works with mass assignment
model.update(attribute: 5)
In your case it could look something like this:
store_accessor :results, :stats
def update
stats = user.test
stats.update_attributes(stats: stats.results.to_i + 1)
end
This question is asked many times on SO. The main problem is nothing got fits into my situation.
Case is, I am not able to store typed content as array in database column.
text_field whose code is:
= text_field_tag 'product[keywords][]', #product.keywords, class: 'tab-input
product_keywords'
In controller strong parameters are:
params.require(:product).permit(:id, :name, :keywords => [])
Jquery code that is not not removing value upon deletion when typed wrong value but it add commas after each element as I want to take commas seperated value in one column.
$(document).on 'keyup', '.product_keywords', ->
keyword = #value.replace(/(\w)[\s,]+(\w?)/g, '$1, $2')
if keyword != #value
#value = keyword
return
model code:
serialize :keywords, Array
migration code:
class AddKeywordsToProducts < ActiveRecord::Migration[5.1]
def change
add_column :products, :keywords, :text
end
end
So, if someone writes, abc and hit space a comma is added in the end. after three typed words it will look like:
abc, dbx, she
now I want to store it as array in column but its not storing properly.
it stores as:
["abc, dbx, she"]
Also please can anybody tell me the best cases to handle these cases?
Plus best practices to deal with such cases using ruby so I will learn it for future?
You probably want a custom serializer as shown here. So instead of:
serialize :keywords, Array
You might do somewhat like:
serialize :keywords, KeywordSerializer
And somewhere in helpers:
class KeywordSerializer
def self.dump(what)
what.join(", ")
end
def self.load(what)
what.split(/\s*,\s*/)
end
end
Passing array elements using single form tag is not possible to pass as a array and passing array as a string, you need to process it near white-listing your params,
permitted_params = params.require(:product).permit(:id, :name, :keywords => [])
permitted_params[:keywords] = permitted_params[:keywords][0].split(/\s*,\s*/)
I want to be able to create attributes on a ActiveRecord:Base Model that are nested.
For example -
class Book < ActiveRecord::Base
attr_accessor :operator, :who
I would like :who to have further attributes like :family, :me
So finally I can access these as follows
book = Book.new
book.who.family = [1,2,3]
book.who.me = 1
I also want to know how can I define the kind of values that attributes can take so I do not have to do that at runtime.
Currently am using something like this
after_initialize do
#who = {family: [], me: nil}
end
I tried it in my console. So if you add the your attributes as attribute accessors and after_initialize set them like this.
attr_accessor :who, :operator
after_initialize do
self.who = {family: [], me: nil}
self.operator = "Minus"
end
then you can access them like this
self.who[:family] = [1,2,3,4]
or
self.operator = "Minus"
and you can simply access them like this
self.who[:family] ==> [1,2,3]
Will this help?
How to handle tag_ids in post params to save it in related model? I would like to use for it only post_params method.
has_many :tags
def post_params
params.require(:post).permit(:title, :message, :tag_ids)
end
#Parameters: {"post"=>{"title"=>"asdf", "message"=>"asfd", "tag_ids"=>"543d727a4261729ecd000000,543d8a914261729ecd010000"}}
I've got:
Mongoid::Errors::InvalidValue -
Problem:
Value of type String cannot be written to a field of type Array
I found solution but I don't like it, in Post model I've added:
def tag_ids=str
str.split(',').each do |id|
t = Tag.find(id)
self.tags << t
end
end
I think that you have to modify the incoming data in tag_ids in create action in your controller.
So when you receive the data, before you are saving the data into DB by, for example: post.create! you should add parsing to your PostsController action create:
If you want array of string:
post.tag_ids = params[tag_ids]split(",")
or if you want array of integers:
post.tag_ids = params[tag_ids]split(",").map(&:to_i)
Something like this? (I'm assuming you want an array of ObjectId)
id_array = params['post']['tag_ids'].split(',').map { |id| BSON::ObjectId.from_string(id) }
params['post']['tag_ids'] = id_array
So I have a array of records and I would like to group by 2 levels
Essentially I would like to group_by{|x| x.field1 } and then each value in hash to be further grouped in by field2. Effectively leading to a tree that I can dump out.
def treemaker(array = [])
tree = ledgers.group_by{|x|x.master_group}
tree.each{|x,z| tree[x] = z.group_by{|y| y.account_group}}
tree
end
I would then render tree in a way that i can be put into a "tree" javascript plugin.
Is there a more efficient way?
Sample Input: An Array of ActiveRecord objects, where the model contains, fields master_group, account_group and name
Class MyModel < ActiveRecord::Base
validates :master_group, :account_group, :name, :presence => true
end
Sample Ouput:
{"master_group1" => {"account_group1" => ["name1","name2",...],
"account_groupx" => ["name3", "name4",...],
....},
"master_group2" => {"account_group2" => ["namex", "namey"]},
...
}
I'm not specifically looking for an "SQL grouping" solution (but that would be nice too). Just a solution using enumerables on a any given list of ruby objects.
#xaxxon sent me thinking in the right way basically with the "default value of hash" path.
I think i can now add a method to my model where i can use all sorts of scopes and tack on tree at the end to get my models in tree mode.
class MyModel < ActiveRecord::Base
validates :master_group, :account_group, :name, :presence => true
def self.tree(field1 = 'master_group', field2 = 'account_group')
tree = Hash.new{|hash,key| hash[key] = Hash.new{|h,k| h[k] = []}}
all.each do |item|
tree[item.send('field1')][item.send('field2')].push(item)
end
tree # bob's your uncle!
end
end
MyModel.recent.tree => Hash of Hash of arrays
set up some fake data
foo=[{:a=>1,:b=>2},{:a=>3,:b=>4}]
set up the output data structure
tree={}
populate the output data structure - this is weird looking because you have to populate the hashes that don't exist when they don't exist, hence the ||={} stuff.
foo.each{|thing| (tree[thing[:a]]||={})[thing[:b]]=thing}
looks good.. :a is your master group and :b is your account_group
pp tree
{1=>{2=>{:a=>1, :b=>2}}, 3=>{4=>{:a=>3, :b=>4}}}