Ruby Mash using - ruby

Im using Grape and can't understand why i can't alter params Mash.
class Publisher < ActiveRecord::Base
end
Following is working fine:
post do
Publisher.create!({
name: params[:name],
partner_id: #current_partner.id
})
end
and creates new record in my DB with name and partner_id provided
but i have many entries in params so i want to just add partner_id to them.
post do
p params
params.partner_id = #current_partner.id
p params
Publisher.create!(params.require(:name, :partner_id))
end
output:
#<Hashie::Mash name="myName">
#<Hashie::Mash name="myName" partner_id=1>
but it insert line in DB with NULL in partner_id column
Is it incorrect use?
Also i can't use just params in update() because of ActiveModel::ForbiddenAttributesError is it correct workaround?

Regarding the params in update(), this is a security feature in Rails called Strong Parameters; see https://blog.8thlight.com/will-warner/2014/04/05/strong-parameters-in-rails.html and http://guides.rubyonrails.org/action_controller_overview.html#strong-parameters for more information.
Regarding your first problem, I think your call to require should be to permit instead:
Publisher.create!(params.permit(:name, :partner_id))
But it depends on if your request parameter names are Rails-like, i.e. publisher[name], or bare as in name. If you are doing Rails-like parameters, you will want:
Publisher.create!(params.require(:publisher).permit(:name, :partner_id))

I have noticed that not only partner_id is null, but name also. So doing Publisher.create!(params.to_h) was solving my problem.

Related

Mongoid "find" returns nil, when "find_by" retrieves record

I'm using Mongoid to access a MongoDB database, however I'm running into an odd problem. It seems like I can only query for records using find_by, as find will always return nil:
invoices = Invoice.find({})
p "invoices"
p invoices
puts ''
invoice = Invoice.find_by({ _id: <ObjectId> })
p "invoice"
p invoice
puts ''
The second query using find_by will return a single record. According to the documentation, find should be returning every record that satisfies the query.
Does anyone have an idea what could be causing this?
Be careful not to confuse the Moped syntax with the Mongoid syntax. For Mongoid, the docs describe the find method:
Find a document or multiple documents by their ids. Will raise an error by default if any of the ids do not match
If you really want every record, Invoice.all can do the trick. (Also be careful with your find_by method. The Mongoid syntax varies from mongo's a bit, so you don't have to have the curlies around your params.)

How to use Sequel to select one field from database

I am using Sinatra and Sequel with PostgreSQL.
After authentication, I want to welcome the user by printing their name but I cannot get only the value of the user's name from the database, it comes out as a hash.
The query is:
current_user = DB[:users].select(:username).where('password = ?', password).first
and the resulting piece of data is:
Welcome, {:username=>"Rich"}
which looks rather weird, I would prefer it to read "Welcome, Rich".
What am I doing wrong here? I tried the same query without 'first" at the end and that does not work either.
You can either pull the (single) column you selected out of the Hash you are given:
current_user = DB[:users].select(:username).where('password=?', password).first[:username]
Or you can map your results to an array of usernames and pull the first:
# Using a hash in the filter method is simpler than SQL placeholders.
current_user = DB[:users].filter(password:password).select_map(:username).first
But the best way is to get only the user you care about, and then get the name:
# Using [] on a dataset returns the first row matching the criteria
current_user = DB[:users][password:password][:username]
Try Sequel::Dataset#get. Also, as Phrogz points out, Sequel::Dataset#where can take a hash (it will securely escape values to prevent injection attacks).
current_username = DB[:users].where(password: password).get(:username)
There's also Sequel::Dataset#where_single_value, which is optimized for this exact situation:
current_username = DB[:users].select(:username).where_single_value(password: password)

How to create an value array for a specific key in ruby hash?

There are user and user_level models in our rails app. In user_level there is a field called user_group_id. The relationship is userhas_manyuser_levels. We would like to generate an array of the user_group_id (in user_level) for a given user_id.
For a given user_id, its user_levels could be retrieved as :
u = User.find(user_id)
ul = u.user_levels
There may be multiple user_levels for a user. How to create an array of user_group_id from ul with ruby map (or some other ruby method(preferable ruby))? thanks.
Try this,
user = User.find(user_id)
user.user_levels.pluck(:user_group_id)
or this,
user.user_levels.map(&:user_group_id)
The first makes a separate database query selecting just the :user_group_id. For example, in MySQL it would call SELECT user_levels.user_group_id ....
The second collects the :user_group_id from the fetched user_levels.
You are indeed looking for map
user_group_ids = ul.map{|x| x.user_group_id}
Or with the shorthand:
user_group_ids = ul.map(&:user_group_id)
You might also want to have only different ids and no nils
user_group_ids = ul.map(&:user_group_id).uniq.compact

don't understand complex Ruby code

I'm currently reading Rails 3 In Action. There is code that I was wondering if someone could explain to me. I'm having a hard time understanding it:
scope :readable_by, lambda { |user| joins(:permissions).where(permissions: { action: "view", user_id: user.id })}
thanks,
mike
It's called a Rails scope. It essentially creates a class method called .readable_by(user) that does a SQL join on the permissions table and returns records where the action column value is "view" and the user_id column value equals user.id.
It could be used like so (assuming it's defined in the Comments model):
readable_comments = Comments.readable_by(current_user)
A simple scope that does nothing is this:
scope :my_scope_name, lambda {}
A scope that accepts a parameter is this:
scope :my_scope_name, lambda { |my_parameter| }
And then the above scope uses some ActiveRecord finder methods, specifically joins and where.

Rails selecting aliases in query

So I have 2 tables actor and actor2role. The latter is a lookup (junction) table to relate actor, role and dvd. I need to create a query with aliases, so I have this method:
def self.remove_duplicate_by_id(id)
offendingActor = self.find(id).actor # get the actor's name
ids = self.find_by_sql("SELECT MIN(id) AS minId, MAX(id) AS maxId, actor FROM `dvd_actor` WHERE actor = '#{offendingActor}'")
rolesForOffender = ids.actor2role # throws error
end
The problem is that ids is not an ActiveRecord object so I can't use the actor2role method (which is a relationship I've established between the 2 tables in Rails and works when you do something like Actor.first.actor2role.
so the questions is: Am I doomed to do this manually and then issue another sql query to recreate what the actor2role method would accomplish or is there some way to do this with Rails objects?
I'd really like to do it all natively if possible because I also have to issue these queries:
UPDATE dvd_actor2role SET actorid = $d->minId WHERE actorId = $d->maxId");
DELETE FROM dvd_actor2role WHERE actorId = $d->maxId LIMIT 1");
Is this even possible?
In the end I went with this which seems to do the trick. If anyone can spot any code that could be optimized, or something inherently wrong (and feels like chiming in) please feel free to comment.
actorObject = self.find_by_id(id) # get the object because we need it below for other queries
offendingActor = actorObject.actor
ids = self.select("MIN(id) AS minId, MAX(id) AS maxId, id, actor").find_by_actor(offendingActor)
rolesForOffender = actorObject.actor2role
rolesForOffender.each do |r|
# first find out if the relationship already exists or we get a SQL error for the foreign key relationship.
exists = Actor2role.where("actorId = ? AND roleId = ?", ids.minId, r.roleId)
if exists.nil?
Actor2role.update_all("actorId = #{ids.minId}, actorId = #{ids.maxId}")
end
end
self.destroy(ids.maxId) # delete this guy in actor table
end

Resources