RoR as_json call missing data that's in the database - json

using rails 4.1.8, ruby 2.2, mysql, elasticsearch-rails 5.0.4, elasticsearch 5.2. the selectors field on the Selector model is stored as json in a varchar column and for some reason when I load a location and its associated selector using as_json, the selectors field comes back nil when I know there is data in the column?
the Selector table:
create table Selectors do
t.text selectors
t.text selectors_other
t.references location
t.timestamps
end
I recently added Elastic Search so the model has:
settings index: {
analysis: {
analyzer: {
selector_analyzer: {
type: :standard,
stopwords: ["some","words","here"]
}
}
}
}
mapping do
indexes :selectors, {analyzer: :selector_analyzer}
indexes :selectors_other, {analyzer: :selector_analyzer}
end
def as_indexed_json(options={})
{
'id' => id,
'selectors' => selectors,
'selectors_other' => selectors_other
}
end
and the call I make to get the data for the view is
Location.find(<id>).as_json(:include => [:selector, :response])
every field I expect is in the json and all the data is there except the selectors field which is nil. I know there is data because if I do:
loc = Location.find(<id>)
loc.selector
the selectors field is not nil. I tried adding an as_json method to the Selector model but it didn't have any effect. The only changes I've made recently were to add the Selector model to the Elasticsearch index. I used an IndexManager in order to create one index with multiple types and created a rake task for deployments and re-indexing. The only distinction is that this field is stored as json, but it was working fine before.
Any ideas, suggestions, etc would be appreciated since I can't think of anything that would cause it to be nil.

figured out what was causing the field to be nil, tho not why it is causing a problem
I had added a method to manipulate the json when updating the selectors field, in that method I had a line like
sel_hash = JSON.parse(self.selectors)
the IDE was unable to resolve self.selectors so I added
attr_accessor :selectors
and that line for some reason caused the selectors field to be nil, go figure

Related

Make doctrine return databasefields as keys for returned data

I'm retrieving data from a Mysql database, and this is done via mapping my entity properties to database fields using Doctrine with annotations as shown in this
image. Retrieving the data is not the problem, but my property name is used as key for the returned data, which is not what i want.
Example:
I have a property gridId (camelCase), which is mapped to a database field called grid_id (snake_case) as shown in the image above. The key for the rows returned for this property will be gridId, and not grid_id, which is desired in my case.
An example of the current situation:
image.
The desired situation:
$grid =
[
grid_block_id = 18
width = 50
width_pixels = 50
]
Changing either the database fields or the property names is not an option in my case.
EDIT
I'm using JMS as serializer. I guess the 4th option of #Jakumi's answer is probably the best option for my use case. Somehow use the serializer to return the property's column name as key for returned values.
My struggle when retrieving data from doctrine is that i have to manually adjust the keys fetched by doctrine as shown in this image as this is how the front-end expects it to be.
so what you're saying is ... you want to actively ignore the object relational mapping (ORM) that the doctrine ORM you're using is providing you and which actually provide the keys exactly the way your entity names them?
I assume there is some good (or not so good) reason for this. Depending on your use case, different solutions may be the best. Options including (but probably very incomplete):
option 1: add a function to the entity
class Grid {
/** all your fields **/
public function toArray() {
return [
'grid_id' => $this->gridId,
// ...
];
}
}
option 2: don't use the orm
add a function in your GridRepository like:
function getRawAll() {
$conn = $this->getEntityManager()->getConnection();
$_result = $conn->query('SELECT * FROM grid');
$results = [];
while($row = $_result->fetch()) {
$results[] = $row;
}
return $results;
}
and similar. Those are obviously circumventing the ORM. The ORM is for retrieving objects, and those have specified fields.
option 3: return the given array back to the unmapped state
use the EntityManager's getClassMetadata (ClassMetadataInfo->fieldMapping) to fetch the mapping for your fields, and "revert" the renaming.
This is probably slightly better than option 1 to some degree, since it doesn't have to be updated.
option 4: use a serializer that does your property name translation.
since you're apparently already using the jms serializer, the SerializedName annotation can probably help, although the default appears to be snake case, but maybe somewhere it's overridden? you might want to check your configuration ...

Database Agnostic 'or' Query in Rails 4.2 Active Record

I have a scope on a Conversation model which maintains an encapsulation of messages between 2 users. I created a scope to help detect a 'Conversation' (to find or check exist) from two user objects.
I used to have:
validates_uniqueness_of :from, scope: :to
scope :between, -> (from,to) { where('("conversations"."from" = ? AND "conversations"."to" = ?) OR ("conversations"."from" = ? AND "conversations"."to" = ?)', from, to, to, from) }
However, while this worked for SQLite and Postgres; it wasn't working for MySQL. I need to convert this explicit query to either be completely database agnostic, or to be made out of active record relations instead.
I have had a shot at doing it myself using '.or' but I suspect this is only available from Rails 5+ because it gave me a undefined method error when I tried to use it.
Instead I have used:
validates_uniqueness_of :from, scope: :to
scope :between, -> (from,to) { where(from: [from, to], to: [to, from]) }
This code works great (and its actually really fast and succinct) but I am worried that it might be 'weak' - in that technically it could allow for a situation where from == from, to == from - which is supposed to be impossible for my application.
If a conversation is created between 'X' and 'Y', then from: X and to: Y = conversation_id: 3 and if Y messages X, then it should find conversation_id: 3 (since semantically they are the same).
Im happy enough to leave the new 'between' scope as is, but how can I strengthen the validation to ensure that from != to when the records are created (and then it doesn't matter that the query could potentially find conversations to and from the same user).
You could try rails_or, a gem which supports #or method in Rails 3, 4, 5.
Then write your scope as:
scope :between, -> (from,to) { where(from: from, to: to).or(from: to, to: from) }

ActiveModelSerializers Polymorphic Json

Been wrestling with trying to get polymorphic serializers working and testing data via rspec. Just upgraded to 0.10+
I found this post, which makes a lot of sense, and does give me a entry into generating the serializations, however, when doing it for polymorphs, I never get the type and id properly named (expecting to see asset_id and asset_type nested)
{:id=>1,
:label=>"Today I feel amazing!",
:position=>0,
:status=>"active",
:media_container_id=>1,
:asset=>
{:id=>4
Test ActiveModel::Serializer classes with Rspec
class MediaSerializer < ApplicationSerializer
attributes :id,
:label,
has_one :asset, polymorphic: true
end
I noticed that the tests dont even seem to properly add the polymorphic identifiers either (ie asset_id, asset_type -- or in the test case imageable_id, imageable_type)
https://github.com/rails-api/active_model_serializers/commit/045fa9bc072a04f5a94d23f3d955e49bdaba74a1#diff-c3565d7d6d40da1b2bf75e13eb8e6afbR36
If I go straight up MediaSerialzer.new(media) I can poke at the .associations, but I cant seem to get them to render as if I was generating a full payload
From the docs
https://github.com/rails-api/active_model_serializers
serializer_options = {}
serializer = SomeSerializer.new(resource, serializer_options)
serializer.attributes
serializer.associations
Im pretty sure Im missing something/doing something wrong - any guidance would be great.
Thanks
It isn't easy to get the effect you are looking for, but it is possible.
You can access the hash generated by the serializer by overriding the associations method.
class MediaSerializer < ApplicationSerializer
attributes :id,
:label,
has_one :asset, polymorphic: true
def associations details
data = super
data[:asset] = relabel_asset(data[:asset])
data
end
def relabel_asset asset
labelled_asset = {}
asset.keys.each do |k|
labelled_asset["asset_#{k}"] = asset[k];
end
labelled_asset
end
end
I learnt alot about ActiveModelSerializer to get the hang of this! I referred to Ryan Bates' podcast on the topic:
http://railscasts.com/episodes/409-active-model-serializers
In there he describes how you can override the attributes method and call super to get access to the hash generated by the serializer. I guessed I could do the same trick for the associations method mentioned in your post. From there it takes a little bit of Ruby to replace all the keys, but, if I have understood correctly what you require, it is technically possible.
Hope that helps!

How to specify Node Label in Neo4jrb

I get a trouble about customize node label in Neo4jrb.
class Core::Product
include Neo4j::ActiveNode
id_property :id
property :name
property :code
property :stock_quantity, type: Integer
property :sale_price, type: Float
property :last_update, type: DateTime
end
When I create new node, it will has label as Core::Product. I want it to be Product instead.
According this post It seem that _classname property could resolve my problem but I have no idea how to implement it.
Any ideas?
Co-maintainer of Neo4j.rb here and author/responsible party for _classname. _classname is a very legacy option at this point, a holdover from when some DB responses didn't include node labels or relationship types. You can override automatic label assignment by calling self.mapped_label_name = in your model.
class Core::Product
include Neo4j::ActiveNode
self.mapped_label_name = 'Product'
# etc,...
end
You'll also want to be aware that the auto-location of association models won't work correctly, so instead of this:
has_many :out, :products, type: 'HAS_PRODUCT'
You'll need to do this:
has_many :out, :products, model_class: 'Core::Product', type: 'HAS_PRODUCT'
We have an open issue, https://github.com/neo4jrb/neo4j/issues/753, that discusses it. I namespace my models to organize code but want my labels to omit them, so I'd love a configuration option that handles this for me.
FOLLOW-UP
I just merged https://github.com/neo4jrb/neo4j/pull/790 into master. It lets you tell the gem to ignore module names when creating labels. I'm going to put it to work in some code this week but if you'd like to test it out, we always love feedback.

return array in rails and storage it

I know that it could sound an "easy-question" but I am new in rails and I don't know if I am structuring correctly my app.
My app is "easy" it has to connect a webpage and collect all JPG links and store the links in a database.
In my "model folder" I have defined my functions:
class JPG < ActiveRecord::Base
acts_as_paranoid
validates :title, :link, presence: true
validates :link, uniqueness: true
attr_accessible :tag_list, :id, :title
#acts_as_taggable
def main_web
require 'rubygems'
require 'scrapi'
require 'uri'
Scraper::Base.parser :html_parser
scraper = Scraper.define do
array :items
process "div.mozaique>div", :items => Scraper.define {
process "div.thumb>a", :link => "#href"
}
result :items
end
uri = URI.parse(URI.encode(web))
return scraper.scrape(uri)
end
end
As you can see the function main_web returns an array.
Well my question is "easy". If I want to call the function and to storage the information in the database, how do I have to do it?
I don't want to show the information in the screen I only want to storage the data in the database but from where do I have to do the call? view? or controller?
I suggest you read more about the controller-view model. You need to call and store in the database from the controller.
If main_web returns an array then wouldn't #jpg = #jpg.main_web mean that #jpg is now an array instead of the Active Record model? That would seem to be why it wouldn't save. You might want to add a field to your database that holds the array you generate from main_web. Then instead of returning it you could just call save on your #jpg model.
Also a nice tip would be if you are having issues with models or other things really try typing 'rails console' on command line. You could run your 3 lines of code there to see if they worked. This wouldn't solve your issue but might allow you to play around with some things.
#jpg = JPG.new
#jpg = #jpg.main_web
#jpg.save
Replacing my initial answer after giving it more consideration...
You are doing this:
return scraper.scrape(uri)
which you assign to the #jpg instance. Thus, #jpg is no longer an instance of JPG and cannot be saved as such.
Also, it is not necessary to call and store from the controller. The controller is more a decision maker than anything. It determines state and routes control and information to the desired view or model. The model is where data should be managed. Though, that may be a matter of debate and is my opinion.
Recommended reading:
http://sirupsen.com/what-I-wish-a-ruby-programmer-had-told-me-one-year-ago/