I am trying to import bulk of records related to the user using activerecord-import gem. Here Role has the has and belongs to many relationship with the user. While importing user data are imported successfully. But role_ids are not imported..
I have tried by getting valid data mail ids and find users from that valid mail ids and update role ids.. It got success.. I need to know some other methods available using active record import.
user params:-
def user_params
params.require(:user).permit(:email, :first_name, :last_name, role_ids: [])
end
import method:-
def import(import)
valid_rows = []
all_roles = {}
file = Paperclip.io_adapters.for(self.file).read
Role.all.select(:id, :name).map { |role| all_roles[role.name.gsub(/[^A-Za-z]/, '').downcase] = role.id }
CSV.parse(file, headers: true, skip_blanks: true, header_converters: ->(header) { header.strip }, converters: ->(data) { data ? data.strip : nil }).each do |row|
user_role_name = (row['roles'].gsub(/[^A-Za-z]/, '').downcase || [])
role_ids = [all_roles[user_role_name]] || []
attributes = { first_name: row['first_name'], last_name: row['last_name'], email: row['email'], role_ids: role_ids}
row = User.new(attributes)
if User.new(attributes).valid?
valid_rows << row
end
User.import valid_rows
end
Can someone please explain how to import roles ids with user data while importing!!
Related
I have these two tables - User, Accounts.
User contains an authentication key,
Accounts contains the list of accounts.
I am trying to get the list of accounts for the user if the authentication key is correct.
So in the controller I have -
def show
#user = User.where(authentication_token: params[:authentication_token])
render json: #user.as_json(
only: [:email, :id, :authentication_token]
),
status: :created
end
This would just return the user details. How can i edit it so it first checks if the user exists with that Authentication_token, and then uses the UserID, in the accounts table to get the list of accounts ?
Your question is a little unclear: What is the desired behaviour if the authentication_token is not correct? Raise an exception? Redirect somewhere? Display a flash message? ...
You could, for example, do something like this:
def show
if authenticated_user
render json: authenticated_user.accounts.as_json(
only: [:id, :foo, :bar]
),
status: :ok
else
render json: { errors: { authentication_token: 'Invalid' } },
status: :unauthorized
end
end
private
def authenticated_user
#authenticated_user ||= User.find_by(
authentication_token: params[:authentication_token]
)
end
I have an a POST /api/v1/users endpoint for creating a user. This is my failing test for it:
test "success" do
user_params = %{
user: %{
email: "eric#spaghetti.com",
image_url: "https://www.google.com/images/spaghetti",
}
}
conn = build_conn(:post, "/api/v1/users", user_params)
response = Router.call(conn, #opts)
assert response.status == 201
assert Repo.get_by(User, %{email: user_params.user.email})
assert response.resp_body == %{
id: "how would I know this??", #<---------this would fail since I have no way of knowing what this value would be
email: user.email,
image_url: user.image_url,
} |> Poison.encode!
end
My endpoint returns 3 fields: email, image_url, and id. I am currently unable to get this test to pass because there's no way I can tell what the ID of the newly created resource will be. Is there a better way to test this?
I normally skip checking for the exact value id in such cases, instead checking only if it exists:
%{email: email, image_url: image_url} = user
assert %{
"id" => _,
"email" => ^email,
"image_url" => ^image_url,
} = Poison.decode!(response.resp_body)
You can also assert that id is an integer:
assert %{
"id" => id,
"email" => ^email,
"image_url" => ^image_url,
} = Poison.decode!(response.resp_body)
assert is_integer(id)
Currently my data structure includes Appointments, which belong to Contracts. I need to access list of all contracts along with the contracts' appointments (appointments filtered by field_rep).
def index # ContractsController
rep_name = # …
render json: Contract.all.map { |c| c.as_json_with_appointments_for_rep(rep_name) }
end
# Contract.rb
def as_json_with_appointments_for_rep(rep_name)
appts = Appointment.where("contract_id=#{ self.id } AND rep_name='#{ rep_name }'")
self.as_json.merge({ appointments: appts })
end
def as_json(options = {})
super(except: [:created_at, :updated_at, :user_id]).merge({ dropoff_date: self.dropoff_date, items: self.active_items, user: self.user })
end
Here, every contract requires a separate database call to get its appointments, resulting in horrible response times.
I'm thinking I'll INNER JOIN appointments and contracts on Appointments.contract_id = Contracts.id but I'm not sure how to bundle the Appointment results into a nested hash in the result. Current output looks like
[ // List of contracts
{
'id': 1,
'appointments': [
{
'id': 1,
// … other appointment fields
},
// … More appointments
]
},
// … More contracts
]
The client is built to handle a contract with no appointments (if a contract has no appointments assigned to the provided rep). Currently using PostgreSQL on Heroku
Seems like you need to to use an outer join. Rails implements this with includes or eager_load.
In your case you can have
#contracts = Contract.a_desired_scope.includes(:appointments)
then
#contracts.to_json
will only require one query to fetch all contracts with their relevant appointments.
instead of to_json you can use whatever iterating method you want, without affecting the number of queries.
In your case you can have a to_json method for each model
#apointment.rb
def to_json
desired_attributes_hash.to_json
end
and
#contract.rb
def to_json
{
id: id
apointments: apointments.map(&:to_json)
}
end
i have a model called Fund and a model called Company .. where fund belongs_to a company.
i have this validation in my Fund table:
validates :name, presence: true, uniqueness: true
This works both on server side and client side using client_side_validations. But i want my fund names to be unique across both fund.name values and fund.company.name values. And i want to do it in a way it would work with client_side_validations too.
Suggestions?
Ended up creating a very specific validator and adding it to client-side-validation. Here'z the breakdown
In models/fund.rb
validates_fund_name_not_company_name :name
new file in config/initializers/validators .. called fund_name_not_company_name_validator.rb
class FundNameNotCompanyNameValidator < ActiveModel::EachValidator
def validate_each(record, attr_name, value)
if ::Company.exists?(name: value)
record.errors.add(attr_name, :fund_name_not_company_name, options.merge(:value => value))
end
end
end
# This allows us to assign the validator in the model
module ActiveModel::Validations::HelperMethods
def validates_fund_name_not_company_name(*attr_names)
validates_with FundNameNotCompanyNameValidator, _merge_attributes(attr_names)
end
end
module ClientSideValidations::Middleware
class FundNameNotCompanyName < ClientSideValidations::Middleware::Base
def response
if ::Company.exists?(name: request.params[:name])
self.status = 404
else
self.status = 200
end
super
end
end
end
then in app/assets/javascripts/rails.validations.custom.js
clientSideValidations.validators.remote['fund_name_not_company_name'] = function(element, options) {
if ($.ajax({
url: '/validators/fund_name_not_company_name',
data: { name: element.val() },
// async must be false
async: false
}).status == 404) { return options.message; }
}
This helped a great deal
I'm trying to filter a feed of posts. A Post and User both have a Boolean field banned_from_feed.
Post has a function:
def banned
self.banned_from_feed or self.user.banned_from_feed
end
Running Post.all.excludes(:banned => true) doesn't filter out these documents, as banned is not a Mongoid Document field.
You probably want a scope:
scope :banned, lambda { any_of {:banned_from_feed => true}, {:user.banned_from_feed => true} }