don't understand complex Ruby code - ruby

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.

Related

Ruby Mash using

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.

Creating a scope on an ActiveRecord Model

I have a ActiveRecord model called Panda with a column called variant, which can consist of values like ‘bam-abc’, ‘bam-123’, ‘boo-abc’ and ‘boo-123’ I want to create a scope which selects all records where the variant starts with ‘boo’.
In the console, I can select those records (starting with ‘boo') with the following:
Panda.select{|p| p.variant.starts_with? 'boo'}
Is there a way to turn that into a scope on the Panda class? I need to be able to do a 'to_sql' on the scope for my RSpec tests.
You'd want to use a scope that sends a LIKE into the database, something like:
scope :boos, -> { where('pandas.variants like ?', 'boo%') }
or equivalently, use a class method:
def self.boos
where('pandas.variants like ?', 'boo%')
end
Then you can say things like:
Panda.boos.where(...)
Panda.where(...).boos
Panda.boos.where(...).to_sql
Panda.where(...).boos.to_sql
You only need to use the pandas prefix on the column name if you think you'll be doing JOINs with other tables that might leave the variant name ambiguous. If you'll never be doing JOINs or you'll only ever have one variant column in your database then you could use one of:
scope :boos, -> { where('variants like ?', 'boo%') }
def self.boos
where('variants like ?', 'boo%')
end
Add the line below to the Panda class
scope :boo, -> { where('variant LIKE ?', 'boo%') }
You can then use Panda.boo to get all the records with variant starting with boo. Panda.boo.to_sql will give you the sql

Dynamic linq/lambda expression from query

I have data query and want to create dynamic linq/lambda expression which i can run on entity collection. Not sure how to do this using Expression builder. Please provide some examples if possible.
For e.g I have query
Select person.name,person.surname from person where person.name= 'Joe'
and i have entity collection of all persons. But dont want to fire a query instead want to convert this query in to lambda and run on persons collection. This to avoid server calls.
linq/lambda expression like
from person in person where person.id ='Joe' select person.name;
It's better to use method syntax rather than query syntax
for example instead of from person in people where person.Name == "Test"
use People.Where(person => person.Name == "Test");
then you can add reference to Mono.CSharp.DLL and then use Evaluator class to compile and run C# codes on the fly easily, without loosing performance too much.
Then compile and run your LINQ queries by C# strings and invoke that string with Evaluator.
You can see this method in JavaScript codes too, with eval function.
Let me know if other information are needed
Good luck
LINQ
var xxx = from p in person
where p.Name equals "Joe"
select p;
Lamda
var lambda = Person.Where(m=> m.Name == "Joe");
For tutorials
MSDN 101 LINQ
MSDN
Lambda

Form helpers in case of Single Table Inheritance

I have to implemene Single Table Inheritance for a class Person who can be of type Teacher, Student,Outsider.
class Person < ActiveRecord::Base
end
class Teacher < Person
end
class Student < Person
end
class Outsider < Person
end
What changes do I need to make in the routes and the forms while register a new user. I have a column(string) "type" in the people table which can be implemented as a dropdown in the form to register a new user. Is there anything else that I need to do in the form so the user is registered as a particular type of Person? Do I need to make any changes in the routes too?
Since you use one form to create all types of Persons, then you should stick with one Controller as well so you don't need to add any additional routes.
The type attribute is not really something you should assign manually to an instance, it should be set automatically by choosing which type of model to create.
I don't know how it looks in your controller and views, but you can extract the type of model to create like this:
class_type = params[:type].constantize
#person = class_type.new
On the other hand, if the type attribute is nested in a form_for in your view, then the type attribute is probably send to the controller like params[:person][:type] in which case it should be removed from the :person hash before it is used to create the new instance. Perhaps something like this:
class_type = params[:person].delete(:type).constantize
#person = class_type.new(params[:person])
Except adding a dropdown list of type selection in the form, there's nothing more to do. You can create a user in the normal way, like:
#user = Person.new params[:user]
But the type attribute could not be mass assigned, so you have to assign it separately.
#user.type = sanitize_user_type params[:user][:type]
The method sanitize_user_type is used to validate user input value.
The route for creating new user doesn't need to change. Whether other routes need to change or not depend on your requirement. Actually you can add the routes for Teacher, Student, Outsider and relative controllers, so that you can build restful urls.

How to use Rails 3 scope to filter on habtm join table where the associated records don't exist?

I have an Author model which habtm :feeds. Using Rails 3 want to setup a scope that finds all authors that have no associated feeds.
class Author < ActiveRecord::Base
has_and_belongs_to_many :feeds
scope :without_feed, joins(:feeds).where("authors_feeds.feed_id is null")
end
...doesn't seem to work. It feels like a simple thing. What am I missing here?
To my knowledge ActiveRecord/Arel do not have a means of defining outer joins. So you'll have to write a bit more SQL than normal. Something like this should do the trick:
scope :without_feed, joins('left outer join authors_feeds on authors.id=authors_feeds.author_id').where('authors_feeds.feed_id is null')
I am of course guessing at your table names and foreign keys. But that should give you the picture.
In Rails >= 5, you can do it like this:
scope :without_feed, -> {
left_outer_joins(:feeds)
.where(authors_feeds: { author_id: nil })
}
scope :with_feed, -> {
left_outer_joins(:feeds)
.where.not(authors_feeds: { author_id: nil })
}

Resources