Rails3/Mongoid - Basic db:seed with embedded documents - ruby-on-rails

I'm using MongoID with rails 3.1. and I would like to seed my database (both in dev and production). I have a Pages model with Feeds embedded. What's the best way for me to seed the embedded feeds for each page? I can easily seed all of the page data just not the embedded feeds. Please note that I'm looking to actual have real unique data for these pages/feeds not just arbitrary test data. thanks!
page.rb (model)
...
embeds_many :feeds
feed.rb (model)
class Feed
include Mongoid::Document
field :source, :type => String
field :user, :type => String
embedded_in :page, :inverse_of => :feeds
end
db/seeds.rb
Page.create(title: "Page 1", userID: "EMAIL#gmail.com", presentation: 'cards', customURL: 'testing1')
Page.create(title: "Page 2", userID: "EMAIL#gmail.com", presentation: 'cards', customURL: 'testing2')
Page.create(title: "Page 3", userID: "EMAIL#gmail.com", presentation: 'cards', customURL: 'testing3')
Page.create(title: "Page 4", userID: "EMAIL#gmail.com", presentation: 'cards', customURL: 'testing4')
Page.create(title: "Page 5", userID: "EMAIL#gmail.com", presentation: 'cards', customURL: 'testing5')
How best can I embed some feed data in each page? Thanks much.

Page.create(title: "blah", feeds: [
Feed.new(source: "blahblah", user: "me!"),
Feed.new(....),
Feed.new(.....),
])
Is how I do it in my db:seed, I even have a few that are multiple documents deep.

You can do something like this:
(1..5).each do |i|
page = Page.create(title: "Page #{i}", userID: "EMAIL#gmail.com", presentation: 'cards', customURL: "testing#{i}")
3.times { Feed.create(page: page) }
end

Related

Searchkick search data working in test but not in browser

I am experiencing some weird behavior with the Elasticsearch wrapper Ruby gem Searchkick, and I'd love your help!
The Issue
The expected behavior is that I should be able to search for a full name with a space in it. This works in my test, but not in browser.
The Code
account.rb
class Account
searchkick word_start: [
:first_name,
:last_name,
:name, # <======================== key line
:email,
:phone,
:company,
], callbacks: :async
def self.index_search(query:)
search(
query || '*',
fields: [
:first_name,
:last_name,
:name, # <======================== key line
:email,
:phone,
:company,
],
match: :word_start,
where: { test_account: false },
order: { created_at: :desc },
limit: 20,
misspellings: false,
)
end
def search_data
{
first_name: first_name,
last_name: last_name,
name: "#{first_name} #{last_name}", # <======================== key line
created_at: created_at,
email: email,
phone: phone,
test_account: test_account,
company: company
}
end
end
account_test.rb - ALL OF THESE PASS
class AccountTest < ActiveSupport::TestCase
describe "::index_search" do
let(:account_0) do
FactoryGirl.create(:account, company: "Xyz Consulting") # name: "Testy McTesterson"
end
let(:account_1) do
FactoryGirl.create(:account, first_name: "Bob") # name: "Bob McTesterson"
end
let(:search) do
Account.index_search(query: query)
end
before :all do
account_0 and account_1 # instantiate
Searchkick.disable_callbacks
Account.reindex
end
describe "when there are spaces in the string" do
let(:query) { "xyz con" }
it "finds all and only the appropriate records" do
assert_equal [account_0.id], search.map(&:id)
end
end
describe "when the query matches the full name" do
let(:query) { "bob mct" }
it "finds all and only the appropriate records" do
assert_equal [account_1.id], search.map(&:id)
end
end
end
end
Note: when I comment out the three 'key lines' from account.rb, the second of those tests fails. So the name: in the #search_data method seems to be working.
search_controller.rb (essentially)
class SearchController < ApplicationController
def index
puts "params[:query]: #{params[:query]}"
puts "custom_search.map(&:first_name): #{custom_search.map(&:first_name)}"
puts "custom_search.map(&:last_name): #{custom_search.map(&:last_name)}"
end
private
def custom_search
Account.index_search(query: params[:query])
end
end
The Complication
Nonetheless, in the browser, it doesn't seem to be working. With the above code, searching via the browser, I can't reproduce the success.
When I search for "bob ", the output in my server console is
params[:query]: bob
custom_search.map(&:first_name): ["Bob"]
custom_search.map(&:last_name): ["McTesterdorff"]
but as soon as I search for "bob m", "bob mct", or "bob mctesterdorff", I get empty results (respecitvely):
params[:query]: bob m
custom_search.map(&:first_name): []
custom_search.map(&:last_name): []
params[:query]: bob mct
custom_search.map(&:first_name): []
custom_search.map(&:last_name): []
params[:query]: bob mctesterdorff
custom_search.map(&:first_name): []
custom_search.map(&:last_name): []
Do you all have any idea what the issue might be?
You need to call Account.reindex once in a while to index/reindex new items. Or you could also add Account.reindex to the according Model within an after_commit callback. This way your new data will be indexed after each insert/commit.

Rails, how to specify which fields to output in a controller's JSON response?

in my controller I currently have:
invite = Invite.find_by_token(params[:id])
user = invite.user
json_response({
user: user
})
def json_response(object, status = :ok)
render json: object, status: status
end
Right now, user is returning all user fields. I want to return just (id, email)... I've tried:
user = invite.user.select(:id, :email)
user = invite.user.pluck(:id, :email)
neither works. Ideas?
You can use the method as_json passing attributes you want in the response, like:
user.as_json(only: [:id, :email])
I know this question already has an answer, but there is also a nice gem you could use called active_model_serializers. This lets you specify exactly which properties you want in your JSON output for different models and even let's you include relationships to other models in your response.
Gemfile:
gem 'active_model_serializers', '~> 0.10.0'
Then run bundle install.
You can then create a serializer using the generator command:
rails g serializer user
which will create the serializer in project-root/app/serializers/.
In your serializer, you can whitelist the attributes you would like:
project-root/app/serializers/user_serializer.rb:
class UserSerializer < ActiveModel::Serializer
attributes :id, :email
end
Now any time you return a User object it will only output those two attributes, id and email.
Want to print out related models? Easy. You can just add the relationship in your serializer and it will include those related models in your JSON output.
Pretend a user "has many" posts:
class UserSerializer < ActiveModel::Serializer
attributes :id, :email
has_many :posts
end
Now your JSON outputs should look something like:
{
"id": 1,
"email": "user#example.com",
"posts": [{
id: 1,
title: "My First Post",
body: "This is the post body.",
created_at: "2017-05-18T20:03:14.955Z",
updated_at: "2017-05-18T20:03:14.955Z"
}, {
id: 2,
title: "My Second Post",
body: "This is the post body again.",
created_at: "2017-05-19T20:03:14.955Z",
updated_at: "2017-05-19T20:03:14.955Z"
},
...
]
}
Pretty neat and convenient. And if you want to limit the the posts to only print certain columns as well, all you need to do is create a serializer for posts, specify the attributes, and the output will just work.

Ruby on Rails Seed Data

I am Ruby/Rails newbie. I am currently learning about the Rails console and databases using Rake and the seeds.rb file.
I am supposed to:
Add a post with a unique title and body to seeds.rb.
Before creating a unique post, verify it exists in the database. Only
seed the post if it doesn't.
Run rake db:seed a couple times, start your Rails console and confirm
that your unique post has only been seeded once.
Repeat to create a unique comment and confirm that it is also only
seeded once.
Honestly I don't know how to start working on this. I am supposed to add a post using the rails console or directly from the seeds.rb file? Any guidance will be greatly appreciated.
Despite the intention of seed-ing - that this is meant to be run once, to populate the database - there is no technical constrain preventing you from running rake db:seed command couple times. Even without cleaning/recreating your database.
In that case, try following code for db/seeds.rb
post_atrributes = [
{ title: "Sample Title 1", body: "Sample body 1" },
{ title: "Sample Title 2", body: "Sample body 2" },
{ title: "Sample Title 3", body: "Sample body 3" },
]
post_attributes.each do |attributes|
Post.create(attributes) unless Post.where(attributes).first
end
First of all, we're defining an array of attributes for each Post, to be created.
Later, we're iterating through that array (with post_attributes.each do |attributes|), and trying create a new Post, unless one with specified attributes found.
In Rails, there is quite fancy method first_or_create, which does exactly that - queries database for specified attributes (where(attributes)), and if nothing found - creates new record based on provided attributes.
post_atrributes = [
{ title: "Sample Title 1", body: "Sample body 1" },
{ title: "Sample Title 2", body: "Sample body 2" },
{ title: "Sample Title 3", body: "Sample body 3" },
]
post_attributes.each do |attributes|
Post.where(attributes).first_or_create
end
At this point, you can "seed" the database with rake db:seed and check what is stored in database (after running rails console) by:
Post.all.map(&:title)
Assuming you had empty database before running rake db:seed, it should contain only 3 Posts. The ones specified with attributes in post_attributes.
Now, if you try to modify your db/seeds.rb again, adding an attributes for one more Post:
post_atrributes = [
{ title: "Sample Title 1", body: "Sample body 1" },
{ title: "Sample Title 2", body: "Sample body 2" },
{ title: "Sample Title 3", body: "Sample body 3" },
{ title: "Another Post", body: "WOW!" },
]
post_attributes.each do |attributes|
Post.where(attributes).first_or_create
end
After running rake db:seed, and checking in console:
Post.all.map(&:title)
You can see, that only one new Post has been created. The one with title "Another Post".
In your question I understood, that when creating new Post, both attributes - title and body have be unique, so if you try to perform the same for attributes like:
post_atrributes = [
{ title: "Sample Title 1", body: "Sample body 1" },
{ title: "Sample Title 1", body: "Sample body 2" },
]
This will create two separate Posts, because they have different body attributes defined.
For Comments you can do similar thing.
Again, as jBeas mentioned earlier - seed-ing has different purpose, but if this is only exercise to play with ActiveRecord - this is one of ways how you can tackle the problem.
Hope that helps!
Seeding is the process of populating a database with data.
There are two methods used to accomplish this.
You can use ActiveRecord Migrations
class AddInitialProducts < ActiveRecord::Migration
def up
5.times do |i|
Product.create(name: "Product ##{i}", description: "A product.")
end
end
def down
Product.delete_all
end
end
Or you can store it in a separate seeds.rb file
5.times do |i|
Product.create(name: "Product ##{i}", description: "A product.")
end
afterwards, run rake db:seed
Source
http://edgeguides.rubyonrails.org/active_record_migrations.html#migrations-and-seed-data

Multikey indexing in rails mongoid

I want to store data in this format.
{
"_id": ObjectId(...)
"title": "Grocery Quality"
"comments": [
{ author_id: ObjectId(...)
date: Date(...)
text: "Please expand the cheddar selection." },
{ author_id: ObjectId(...)
date: Date(...)
text: "Please expand the mustard selection." },
{ author_id: ObjectId(...)
date: Date(...)
text: "Please expand the olive selection." }
]
}
I'm confused as to how to achieve this format for my data.
I am using mongoid; does Mongoid support Multikey Indexing?
How can use mongoid to achieve my desired format and behaviour?
I'm not sure if I got your doubt correctly but as I can't comment I'm answering right away. If it isnt this what you asked, please explain a little bit more =)
You have your model with those fields you wrote before, I will call it Post model. For the comments on it, I would suggest you create another model callend Comment and embed it on the Post model:
class Post
field: title
embeds_many :comments
end
class Comment
field :date
field :text
has_one :author
embedded_in :post
end
And to index the comments on the Post model you could do:
index({ :"comments.updated_at" => 1 })

Rails doesn't use human name for error message

in my translation file
activerecord:
models:
subject_choice: "Subject Choice"
subject_preference: "Subject Preference"
art_subject_choice: "Group 1 Preference"
science_subject_choice: "Group 2 Preference"
attributes:
student:
in_class: "Class"
subject_prefernce:
math_preference_type:
m1: "M1"
m2: "M2"
m1_m2: "M1>M2"
m2_m1: "M2>M1"
subject:
subject_type:
science: "Science"
art: "Art"
elective: "Elective"
the validation is done in subject_preference model. but the error show on page is "Subject preference base Art priority cannot be same as science priority."
How can I make it display model name correctly?
UPDATE:
I just want to get rid of "Subject preference base", how can i do it? Thanks
errors[:base] << "Duplicated priority in science subject"
I tried a different approach, for example
en:
activerecord:
models:
message:
attributes:
message:
content: ""
subject: ""
and in my model:
validates :subject, :presence => { :message => I18n.t('validation.category')}
This approach ensures only the validation message itself is shown.

Resources