Rails getting single values from request - ruby-on-rails-3

in Rails the create method in a Controller by default receives an HTTP request with different values.
By default new records are created like this:
#apo = Apo.new(params[:apo])
But how can i access single Values from this params hash?
I would like to create something like this:
#apo = Apo.new do |a|
a.name = $someVariable
a.value = $anotherVariable
a.quantity = -> here i want to have one value which is in params[:apo]
end
Do you understand what i´m looking for?
Tried million possibilities but it just doesn´t work.
Alternatively, is it possible, to create a second params hash in the view, which only saves this one value?
P.S. i don´t want to use JavaScript for doing this...
Thanks a lot!

params is special, and is set by Rails for each HTTP request. It's a hash in the form
{ :object => { :attrib1 => "value1", :attrib2 => "value2" ... }}
So you can reference the entire object with
params[:foo]
and individual attributes (fields) like
params[:foo][:bar]
A ActiveRecord model can be created in one call by passing a hash of values, as in your first example. But there are many other ways to create an instance. You can
def make_apo(some_value, another_value)
apo = Apo.new
apo.name = some_value
apo.value = another_value
end
Such a method will return an instance of Apo. In your case, if you have some values in params, change the above to accept params as another argument, or pass specific values when you call.
def make_apo(some_value, another_value, quantity, passed_params)
apo = Apo.new
apo.name = some_value
apo.value = another_value
apo.quantity = passed_params[:apo][:quantity]
end
But this is all a pretty unusual way of going about things. So don't just do this -- it's more by way of explaining what's going on than suggesting that you do this.

Related

Default values for query parameters

Please forgive me if my question does not make sense.
What im trying to do is to inject in values for query parameters
GET1 File
Scenario:
Given path 'search'
And param filter[id] = id (default value or variable from another feature file)
POST1 File
Scenario:
def newid = new id made by a post call
def checkid = read call(GET1) {id : newid}
like if one of my feature files creates a new id then i want to do a get call with the above scenario. therefore i need a parameter there which takes in the new id.
On the other hand if i do not have an id newly created or the test creating it is not part of the suite. i want to still be able to run the above mentioned scenario but this time it has a default value to it.
Instead of param use params. It is designed so that any keys with null values are ignored.
After the null is set on the first line below, you can make a call to another feature, and overwrite the value of criteria. If it still is null, no params will be set.
* def criteria = null
Given path 'search'
And params { filter: '#(criteria)' }
There are multiple other ways to do this, also refer to this set of examples for data-driven search params: dynamic-params.feature
The doc on conditional logic may also give you some ideas.

How to send a query to the database using GET through an REST API (Ruby on Rails)

I would like to add a query parameter to a GET request such a way that my REST API returns the query's result instead of the result from default index method.
Is this possible?
Here is my index method:
def index
users = User.all
render(
json: ActiveModel::ArraySerializer.new(
users,
each_serializer: Api::V1::UserSerializer,
root: 'users'
)
)
end
I would like to have an additional method named my_new_index executable by a GET or I would like to have a query submitted as a parameter to the default index method, lets say something like this:
query = "select * from users where name like 'A%' order by name desc"
I'm not sure I understand exactly what you're trying to do but what I would suggest is using the same end point index to return your content filtered.
First I'll start by creating a scope like:
scope :starting_with, ->(letter) { where('users.name like ?', "#{letter}%") if letter }
Then update you index end point to something like:
def index
users = User.starting_with(params[:letter]).all
render(
json: ActiveModel::ArraySerializer.new(
users,
each_serializer: Api::V1::UserSerializer,
root: 'users'
)
)
end
In this quick example the end point receive the params, if it contains a letter params, it will render users filtered by the scope query. If the param is not present, it return all users.
FYI it's just a quick example and not perfect, I'm sure you could find ways improve it.
Hope it helps :)

django "use_natural_foreign_keys=True" issue

I currently use the well documented "use_natural_foreign_keys=True" to return the relevant field data required instead of the id:
all_orders = Orders.objects.all()
resp = serializers.serialize('json', all_orders, use_natural_foreign_keys=True)
What I don't know how to do is return both the id AND the field data required as typically returned by the "use of use_natural_foreign_keys=True".
Anyone know of a quick fix to return both?
Many thanks, Alan.
define a "natural_key" method in your model class, whose id and field_name you like to get. e.g
def natural_key(self):
return (self.id, self.field_name)

Rails SQL efficiency for where statement

Is there a more efficient method for doing a Rails SQL statement of the following code?
It will be called across the site to hide certain content or users based on if a user is blocked or not so it needs to be fairly efficient or it will slow everything else down as well.
users.rb file:
def is_blocked_by_or_has_blocked?(user)
status = relationships.where('followed_id = ? AND relationship_status = ?',
user.id, relationship_blocked).first ||
user.relationships.where('followed_id = ? AND relationship_status = ?',
self.id, relationship_blocked).first
return status
end
In that code, relationship_blocked is just an abstraction of an integer to make it easier to read later.
In a view, I am calling this method like this:
- unless current_user.is_blocked_by_or_has_blocked?(user)
- # show the content for unblocked users here
Edit
This is a sample query.. it stops after it finds the first instance (no need to check for a reverse relationship)
Relationship Load (0.2ms) SELECT "relationships".* FROM "relationships" WHERE ("relationships".follower_id = 101) AND (followed_id = 1 AND relationship_status = 2) LIMIT 1
You can change it to only run one query by making it use an IN (x,y,z) statement in the query (this is done by passing an array of ids to :followed_id). Also, by using .count, you bypass Rails instantiating an instance of the model for the resulting relationships, which will keep things faster (less data to pass around in memory):
def is_blocked_by_or_has_blocked?(user)
relationships.where(:followed_id => [user.id, self.id], :relationship_status => relationship_blocked).count > 0
end
Edit - To get it to look both ways;
Relationship.where(:user_id => [user.id, self.id], :followed_id => [user.id, self.id], :relationship_status => relationship_blocked).count > 0

ActiveRecord .select(): Possible to clear old selects?

Is there a way to clear old selects in a .select("table.col1, ...") statement?
Background:
I have a scope that requests accessible items for a given user id (simplified)
scope :accessible, lambda { |user_id|
joins(:users).select("items.*")
.where("items_users.user_id = ?) OR items.created_by = ?", user_id, user_id)
}
Then for example in the index action i only need the item id and title, so i would do this:
#items = Item.accessible(#auth.id).select("polls.id, polls.title")
However, this will select the columns "items., items.id, items.title". I'd like to avoid removing the select from the scope, since then i'd have to add a select("items.") everywhere else. Am I right to assume that there is no way to do this, and i either live with fetching too many fields or have to use multiple scopes?
Fortunately you're wrong :D, you can use the #except method to remove some parts of the query made by the relation, so if you want to remove the SELECT part just do :
#items = Item.accessible(#auth.id).except(:select).select("polls.id, polls.title")
reselect (Rails 6+)
Rails 6 introduced a new method called reselect, which does exactly what you need, it replaces previously set select statement.
So now, your query can be written even shorter:
#items = Item.accessible(#auth.id).reselect("polls.id, polls.title")