This runs fine on the rails server but doesn't work on Heroku and says something went wrong etc. This basically happens when I search for b_pages via BPage_name:
Schema:
create_table "b_pages", force: :cascade do |t|
t.string "Bpage_name"
t.string "first_post"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "profile_img_file_name"
t.string "profile_img_content_type"
t.integer "profile_img_file_size"
t.datetime "profile_img_updated_at"
t.string "banner_img_file_name"
t.string "banner_img_content_type"
t.integer "banner_img_file_size"
t.datetime "banner_img_updated_at"
t.integer "user_id"
t.string "status"
t.text "bio"
t.string "relationship"
t.text "whitelist"
t.text "blacklist"
end
b_page.rb:
def self.search(query)
where("Bpage_name like ?", "%#{query.downcase}%")
end
Identifiers (such as table and column names) are case insensitive in SQL. However, if you double quote them when you create the table then they are case sensitive. Standard SQL folds unquoted identifiers to upper case but PostgreSQL folds them to lower case, hence the complain about bpage_name being an unknown column when you say:
where("Bpage_name like ?", "%#{query.downcase}%")
ActiveRecord double quotes all the identifiers when it creates tables so if you have any column names that are case sensitive (such as Bpage_name) then you have to double quote them everywhere you use them in SQL snippets:
where('"Bpage_name" like ?', "%#{query.downcase}%")
# -----^----------^
The recommended practice with PostgreSQL (and Rails/ActiveRecord for that matter) is to use lower case column names with underscores to separate words. Saying this:
t.string "bpage_name"
in your migration would be more consistent with both conventions and would avoid your quoting problem completely.
When you say something like:
where(:Bpage_name => 'pancakes')
ActiveRecord will add the quotes itself and send:
where "Bpage_name" = 'pancakes'
to the database. The quoting and case sensitivity issue only arises when you use bits of SQL; of course, you almost always end up using SQL snippets with ActiveRecord so the naming convention is still important if you don't want to litter your code with a bunch of noisy double quotes.
Related
I have a show page generated from a very large database, queried by #listing = Listing.find(params[:listing_id]) in the controller. At the bottom of the page I also have links to three other listings; for now they are queried by #listings = Listing.last(3), but I am trying to pick three similar listings - by community, or by a price range.
example - Listing.where(:price => 500000..600000).limit(2)
However...I am at a loss as to how to do this in comparison to the active page listing. How would I pick listings from the same community, or within a certain price range of the same record, for instance? If someone could direct me as to how to make this connection I would appreciate it (I'm fairly junior, but also am really learning to enjoy ActiveRecord, and want to expand what I can do with it).
Before anyone asks, here's my schema:
create_table "listings", force: :cascade do |t|
t.string "mls"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "community"
t.string "description"
t.integer "price"
t.string "status"
t.string "address"
end
It looks like you need something like this:
price_range = (#listing.price - 100)..(#listing.price + 100)
Listing.where(price: price_range, community: #listing.community).limit(3)
You were on the right track!
I'm getting started with Rails again and am running into a conundrum I find intimidating at the moment. I'm somewhat of a noob when it comes to working with databases, so please forgive me if this is fairly basic.
I have an older Rails app with a data model I no longer wish to conform to. The model should be deprecated in favor of a lighter, less complex one.
The older app is also very monolithic, so I'm trying to break it up into smaller service components.
So this leads me to my question, since it's generally frowned upon to use multiple databases from a single model… what would be the best method for translating data stored in the old model to my new model, one service at a time?
For example, let us suppose I have a user model in both the old and the new. In the old model, the user has many columns, not all of which should make it to the new model.
An example of this could be a change from a user being limited to a single address in the old model to being able to assign a one to many relationship where addresses are split off in their own model and simply referenced using a foreign key or something.
EDIT 1:
The goal ultimately is to siphon the data from the legacy model's database into the new model's database as easily as possible, one dataset at a time.
EDIT 2:
Originally posted from my mobile. Here are a couple examples which may help with suggestions.
OLD MODEL
create_table "brands", force: :cascade do |t|
t.string "name"
t.string "url"
t.string "logo"
t.boolean "verified"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "hidden", default: false
t.string "facebook_url"
t.string "twitter_handle"
t.string "pinterest_handle"
t.string "google_plus_url"
t.string "address_street1"
t.string "address_street2"
t.string "address_street3"
t.string "address_city"
t.string "address_state"
t.string "address_zip"
t.string "address_country"
t.string "email"
t.string "phone"
t.string "story_title"
t.text "story_text"
t.string "story_photo"
end
NEW MODEL
create_table "companies", force: :cascade do |t|
t.string "companyName", null: false
t.string "companyURL", null: false
t.boolean "companyIsActive", default: true, null: false
t.boolean "companyDataIsVerified", default: false, null: false
t.string "companyLogoFileURL"
t.datetime "companyFoundedOnDate"
t.integer "companyHQLocationID"
t.integer "companyParentCompanyID"
t.integer "companyFirstSuggestedByID"
t.string "companyFacebookURL"
t.string "companyGooglePlusURL"
t.string "companyInstagramURL"
t.string "companyPinterestURL"
t.string "companyTwitterURL"
t.string "companyStoryTitle"
t.text "companyStoryContent"
t.string "companyStoryImageFileURL"
t.boolean "companyIsHiddenFromIndex", default: false, null: false
t.integer "companyDataScraperID"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
So, basically... I want to be able to take data from the old model, say a brands "name" column and siphon its related values to the new model so the value ends up in the companies "companyName" column of a totally different postgresql instance.
Having done this multiple times, I can tell you that the easiest thing to do is to create a simple rake task that iterates the first collection and creates items in the new collection.
There is no need to use anything like DataMapper. You already have ActiveRecord and can simply define which DB connection to use for each model.
In your config/database.yml:
brand_database:
adapter: postgresql
host: brand_host
username: brand_user
password: brand_pass
database: brand_db
company_database:
adapter: postgresql
host: company_host
username: company_user
password: company_pass
database: company_db
In your models:
class Brand < ActiveRecord::Base
establish_connection :brand_database
end
class Company < ActiveRecord::Base
establish_connection :company_database
end
In your new rake task (lib/tasks/db.rake):
# lib/tasks/db.rake
namespace :db do
desc "Migrate brand records to company records"
task :migrate_brands_to_companies, [] => :environment do
Brand.find_each do |brand|
Company.find_or_initialize_by(companyName: brand.name) do |company|
puts "\n\tCreating Company record for #{brand.name}"
company.companyURL = brand.url
company.companyLogoFileURL = brand.logo
company.companyTwitterURL = "https://twitter.com/#{brand.twitter_handle}"
company.companyIsHiddenFromIndex = brand.hidden
company.created_at = brand.created_at
company.updated_at = brand.updated_at
company.save!
end
end
end
end
Finally, run the rake task:
$ rake db:migrate_brands_to_companies
I need to say this: Rails is built using a solid convention. Failing to adhere to that convention will cause problems and additional expense, everytime. I have seen this many many times. Every single time I have seen someone deviate from that convention, they run into far more trouble than they would have ever expected. They break a lot of the "Rails magic".
Taking a TDD approach would certainly help you cover more ground.
Look at DataMapper, which you can use in a Rake task or completely separate Ruby-script. This way, you can iterate over the app data (from Active Record) and pass it to the new Postgres DB via DataMapper.
You can connect to the new DB like this,
DataMapper.setup(:default, 'postgres://user:password#hostname/database')
I am creating a political Rails app that will allow users to compare candidates' positions on issues. At the heart of it is a table, representing the Active Record table, where the rows represent five presidential candidates and columns represent issues. Each <td> will represent whether or not the specific candidate has stated a position on the issue. If not, of course, it will be nil.
The problem:
I have code for candidate.issues.each and issue.position, but I can’t seem to create new positions for candidates without overriding other ones.
The goal is to include both candidates and both positions, so that the user can get a closer look at where they stand on the issue.
ActiveRecord::Schema.define(version: 20160827005554) do
create_table "candidates", force: :cascade do |t|
t.string "fname"
t.string "lname"
t.string "title"
t.string "minitial"
t.string "party"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "issues", force: :cascade do |t|
t.string "issname"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "candidate_id"
t.string "position"
end
end
Models: Issue belongs to candidate
Candidate: has_many issues (or should it be positions for each issue?)
Examples, in the Rails console:
i = Issue.find(1) *Agriculture
c = Candidate.find(2) *Trump
c.i.position = “(a couple paragraphs of text)” => error.
Example 2, also in the console:
i = Issue.find(1) *Agriculture
i.candidate_id = 1 *Clinton
i.position = “(some paragraphs of text)"
i.save
i.candidate_id = 2 *Trump
i.position = “(some other paragraphs of text)"
i.save *overrides candidate_id(1) and, with it, Clinton’s position.
By the way, I intend to save paragraphs in the console so that I could give detailed positions on the issues. Is it feasible to include <b> tags, <i> tags, etc.?
Ex. Clinton on agriculture:
ENERGY
Clinton has touted the benefits of cleaner energy sources and posited them as a boon for agricultural economies. Most notably, her plan calls for the expansion of solar panels by half a billion by 2021. She supports expanded biofuel research and use.
FOOD POLICY
Clinton favors keeping federal food programs, like the Supplemental Nutrition Assistance Program (SNAP) program, funded. She also wants to increase local food options through different channels - grants that aim to connect consumers directly to farmers, increased funds for USDA marketing programs, and other non-specified avenues.
She has indicated support for the use of genetically modified organisms (GMOs).
It seems that you want to keep issues unique and at the same time save each candidate's position for the issue.
That will only work if you duplicate issues in the table. Like this:
trump = Candidate.find 1
clinton = Candidate.find 2
Issue.create(issname: 'Agriculture', candidate: trump, popsition: 'some text')
Issue.create(issname: 'Agriculture', candidate: clinton, position: 'text')
But for me it's not ideal. You'd better add another model - Position
class Position
belongs_to :candidate
belongs_to :issue
end
class Candidate
has_many :positions
end
class Issue
has_many :positions
end
create_table "positions", force: :cascade do |t|
t.integer "issue_id"
t.integer "candidate_id"
t.string "text"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Than you can write like this:
agriculture = Issue.find_by(issname: 'Agriculture')
trump = Candidate.find_by(lname: 'Trump')
trump.positions.where(issue: agriculture).create!(text: 'text')
I'm building a job board in the rails framework. I'm setting up my job scaffold and running into an issue.
The employer will be able to set the job_title, job_location, salary, description, required_education, required_major required_experience, and so forth. In some job postings, you'll see employers put in their description, "Minimum Education Requirement is a BS in Computer Science or related field." I'm trying to add numerous fields in my db under the required_major column so the employer can add the related degrees. For example, if the employer will accept a Bachelors degree in Computer Science, Software Engineering, Computer Engineering, or Information Technology; I want to be able to add multiple majors for the required_major field. Would I be able to create a subfield of this column so it would have all the degrees listed or should I have numerous columns (ex. required_major1 required_major2, etc.).
Here is my current schema for the jobs table:
ActiveRecord::Schema.define(version: 20160103030240) do
create_table "jobs", force: :cascade do |t|
t.integer "company_id"
t.string "job_title"
t.string "job_location"
t.decimal "salary", precision: 8, scale: 2
t.text "description"
t.string "required_education"
t.string "required_major"
t.string "required_experience"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Right now, I'm just going to start with a single degree field and expand on it as I build. Any input on this would be appreciated.
I have a DuesPayment and a Donation model. I want to list members in descending order by total of dues + donations. Is this something active record can do exclusively or will I have to make some addition and sorting code in the app?
The db is Postgres
You can make this happen using the select, where and order clause. Suppose we had a table with this schema:
create_table "leaders", :force => true do |t|
t.integer "leaderable_id"
t.string "leaderable_type"
t.integer "county_id"
t.integer "us_state_id"
t.integer "recruits"
t.integer "hours"
t.datetime "created_at"
t.datetime "updated_at"
t.datetime "last_run_dt"
end
If you want to order the results you would run a query like this:
Leader.select("(hours + recruits) as hr").order("hr")
If you want to select records based on the sum then you can ran a query like this:
Leader.select("(hours + recruits) as hr").where("(hours +recruits) > 1100")
You can access the result like:
Leader.select("(hours + recruits) as hr").order("hr").first.hr