Fetch data from a database in rails - mysql

I have created a rail application
i am connecting to mysql database
i already have 2 tables users and history
how can i fetch data from these tables
i can save data to database
with
def register
if(params[:register])
#registermsg=Users.where(:username=>params[:register][:username])
if #registermsg.length>0
flash[:success] = "Username exists:#{params[:username]}:"
else
#reg = Users.create(user_params)
#reg.save
flash[:success] = "success:#{params[:register][:username]}:"
end
end
end
def user_params
params.require(:register).permit(:username, :password, :password2)
end
but when i am fetching data from users
def login
if session[:user]
redirect_to '/dash'
end
if(params[:login])
#login1=Users.where("username=? AND password=?",params[:login][:username],params[:login][:password])
if #login1.length==1
session[:user] = #login1
hist = History.create(userid: **#login1.id**, ip: request.remote_ip )
// here #login1.id is giving me error
redirect_to '/dash'
else
flash[:success] = "Wrong"
end
end
end
#login1=Users.where("username=? AND password=?",params[:login][:username],params[:login][:password])
#login1.to_yaml is printing full data
how can i get id,username etc from #login1
presently #login1.id is getting error
I researched in many websites including stack overflow till now i didnt got any solution please help

Here #login1 is an ActiveRelation object. You will have to call first to get the actual user object
if #login1.count==1
session[:user] = #login1.first
hist = History.create(userid: #login1.first.id, ip: request.remote_ip )
redirect_to '/dash'

Related

ActiveRecord::AssociationTypeMismatch Rails CSV Import

I am using gem roo to import CSV data. It works smoothly, until the point where there is an association, and am hoping that roo can translate the string into the corresponding integer value in the association. In my case, I have a Staff model which belongs to State.
class State < ApplicationRecord
has_many :staffs
end
class Staff < ApplicationRecord
belongs_to :state
end
This means that I have state_id column in the staffs table. In my CSV, however, the end user has the names of the states, which correspond to the ones in the states tables. When I try to import the CSV, I get the error:
ActiveRecord::AssociationTypeMismatch in StaffsImportsController#create
State(#134576500) expected, got "Texas" which is an instance of String(#20512180)
The highlighted source is:
staff.attributes = row.to_hash
Is it possible for gem roo to translate 'Texas' in the csv file to, say, id 2, instead of the end user doing a lot of translation work before uploading the data?
Here is staffs_imports.rb
class StaffsImport
include ActiveModel::Model
require 'roo'
attr_accessor :file
def initialize(attributes={})
attributes.each { |name, value| send("#{name}=", value) }
end
def persisted?
false
end
def open_spreadsheet
case File.extname(file.original_filename)
when ".csv" then Csv.new(file.path, nil, :ignore)
when ".xls" then Roo::Excel.new(file.path, nil, :ignore)
when ".xlsx" then Roo::Excelx.new(file.path)
else raise "Unknown file type: #{file.original_filename}"
end
end
def load_imported_staffs
spreadsheet = open_spreadsheet
header = spreadsheet.row(1)
(2..spreadsheet.last_row).map do |i|
row = Hash[[header, spreadsheet.row(i)].transpose]
staff = Staff.find_by_national_id(row["national_id"]) || Staff.new
staff.attributes = row.to_hash
staff
end
end
def imported_staffs
#imported_staffs ||= load_imported_staffs
end
def save
if imported_staffs.map(&:valid?).all?
imported_staffs.each(&:save!)
true
else
imported_staffs.each_with_index do |staff, index|
staff.errors.full_messages.each do |msg|
errors.add :base, "Row #{index + 6}: #{msg}"
end
end
false
end
end
end
And finally the staff_imports_controller.rb:
class StaffsImportsController < ApplicationController
def new
#staffs_import = StaffsImport.new
end
def create
#staffs_import = StaffsImport.new(params[:staffs_import])
if #staffs_import.save
flash[:success] = "You have successfully uploaded your staff!"
redirect_to staffs_path
else
render :new
end
end
end
Any help/clues will be highly appreciated.
I managed to get a solution to this, thanks to a wonderfully detailed question and great answer provided here Importing CSV data into Rails app, using something other then the association "id"

ActiveRecord: Connect to multiple databases one by one

I need to ensure that records on different database servers are present on the backup server.
I'm trying to execute this as a Sinatra project using RSpec:
describe 'BACKUP' do
puts 'BACKUP config'
puts DB_CONFIG[:BACKUP].inspect
p "Key.count #{Key.count}"
DB_CONFIG[:databases].each do |server,config|
p "****************************************************************"
p "Server #{server} "
p " Config #{config.inspect}"
p "Service.count #{Service.new(config).count}"
end
end
Where:
class Key < BillingTables
end
class BillingTables < ActiveRecord::Base
self.abstract_class = true
establish_connection DB_CONFIG[:BACKUP]
end
is connected to one database.
On the other hand I'm connecting simultaneously to another database with this class:
class Service < CoreTables
end
class CoreTables < ActiveRecord::Base
self.abstract_class = true
def initialize(params = {})
establish_connection params
end
end
Output of this script is as follows:
=== Comparison Spec ===
backup config
{"adapter"=>"mysql2", "encoding"=>"utf8", "reconnect"=>true, "database"=>"backup", "pool"=>1, "username"=>"backup", "password"=>"password", "host"=>"xxx.xxx"}
"Key.count 3902"
"****************************************************************"
"Server a1 "
" Config {\"adapter\"=>\"mysql2\", \"encoding\"=>\"utf8\", \"reconnect\"=>true, \"database\"=>\"s1\", \"pool\"=>1, \"username\"=>\"s1\", \"password\"=>\"password\", \"host\"=>\"yyy.yyy\"}"
/Users/password123/.rvm/gems/ruby-2.2.3/gems/activerecord-4.2.4/lib/active_record/connection_adapters/abstract/connection_pool.rb:570:in `retrieve_connection': No connection pool for Service (ActiveRecord::ConnectionNotEstablished)
In the end, I dropped my idea of multipe active_records, and now I'm just performing mysql connections
begin
client = Mysql2::Client.new DB_CONFIG[:databases][server]
query = 'SELECT * FROM test'
result = client.query(client.escape(query),symbolize_keys: true)
rescue Exception => e
p "query error #{e.message}"
next
end

ActiveRecord: Column 'nivelAcceso' cannot be null

I need to add a 'Change password' feature to the app I'm currently building, but when I try to change an user's password, I get the following error:
Column 'nivelAcceso' cannot be null; While the user's password and 'nivelAcceso' (the access the user has in the application) are found on the same table (usuarios) they aren't related in any way.
The route that handles the password change looks like this:
app.rb
put '/:id' do
change_password(params[:id], params[:password], params[:confirm])
end
While the controller looks like:
password_controller.rb
def change_password(id, password, confirm)
if password.nil? || confirm.nil?
redirect '/dashboard/change_password', error: 'Debe completar todos los campos.'
elsif password != confirm
redirect '/dashboard/change_password', error: 'Los campos no coinciden.'
else
u = User.find(id)
new_password = BCrypt::Password.create(password)
u.passwordUsuario = new_password
if u.save
redirect '/dashboard/change_password', notice: 'Cambio de contraseƱa exitoso.'
else
redirect '/dashboard/change_password', error: 'Ha ocurrido un error, intente nuevamente.'
end
end
end
I have tried the following with no avail so far:
u.nivelAcceso = session[:rol] # 'nivelAcceso' value is stored in the session
ActiveRecord says the column can't be null. This is usually due to the database being configured this way.
If you configured the database using ActiveRecord migrations, look for something like this:
create_table(:cars) do |t|
# other commands
t.string :foo, null: false
end
You can change this by writing and running a new migration:
change_column :table_name, :foo_column, :string, null: true
Turns out the route to change the password is exactly the same as the route to edit an user.
Original, non-working route:
put '/:id' do
change_password(params[:id], params[:password], params[:confirm])
end
Edited, working route:
put '/change_password/:id' do
change_password(params[:id], params[:password], params[:confirm])
end

Writing rspec test for CSV upload file

I have the code that implement csv upload like this:
def Hotel.import(file)
CSV.foreach(file.path, headers: true) do |row|
product = find_by_id(row["id"]) || new
product.attributes = row.to_hash
product.save
end
end
def import
Hotel.import(params[:file])
redirect_to root_url, notice: "Product was successfully Imported."
end
so how do I write rspec test for this?
There are lots of ways to write controller specs. There are many good resources online outlining how to write them in different styles. I suggest starting with the RSpec docs on controller specs:
https://github.com/rspec/rspec-rails#controller-specs
https://www.relishapp.com/rspec/rspec-rails/v/2-14/docs/controller-specs
In general they go something like:
require "spec_helper"
describe ProductsController do
describe "POST #import" do
it "redirects to the home page" do
allow(Hotel).to receive(:import).with("foo.txt")
post :import, file: "foo.txt"
expect(response).to redirect_to root_url
end
it "adds a flash notice" do
allow(Hotel).to receive(:import).with("foo.txt")
post :import, file: "foo.txt"
expect(flash[:notice]).to eq "Product was successfully imported."
end
it "imports the hotel file" do
expect(Hotel).to receive(:import).with("foo.txt")
post :import, file: "foo.txt"
end
end
end
If any one needed model tests for rspec.
require 'rails_helper'
RSpec.describe Product, type: :model do
describe 'import' do
before :each do
#file = fixture_file_upload('data.csv', 'csv')
end
context 'when file is provided' do
it 'imports products' do
Product.import(#file)
expect(Product.find_by(part_number: '0121G00047P').description)
.to eq 'GALV x FAB x .026 x 29.88 x 17.56'
end
end
end
end

Rspec: Carrierwave doesn't save file from spec/fixtures

I have my Report model:
class Report < ActiveRecord::Base
belongs_to :user
attr_accessible :ready_status, :document
mount_uploader :document, DocumentUploader
def attach( report_file )
self.update_attributes( :document => File.open( report_file ), :ready_status => true )
end
end
This model has attach metod, which i use to save document and other param. Now i want to test that this function works.
/spec/models/report_spec.rb
# encoding: utf-8
require 'spec_helper'
describe Report do
before(:each) do
#user = User.make!
end
...
context "File's saving" do
before(:each) do
#report = #user.reports.create
#csv_report_file = "#{Rails.root}/spec/files/report.csv"
end
it "CSV should be saved" do
csv_report_filename = #csv_report_file.split("/").last
#report.attach #csv_report_file
#report.reload
#report.document.file.filename.should == csv_report_filename
end
end
end
When i try to saving file from /spec/files i get such error:
Report File's saving CSV should be saved
Failure/Error: #report.document.file.filename.should == csv_report_filename
NoMethodError:
undefined method `filename' for nil:NilClass
But when i try another file from another folder (for example "#{Rails.root}/samples/my-report.csv") then my test passes.
How can i fix that?
Oh, i found the answer. Carrierwave doesn't save empty file and i had one. When i added some data in the file (/spec/files/report.csv) my problem has gone.