rails 4 redirect back with new params - ruby-on-rails

Is it possible to redirect back to the referring url with a new param in the query string?
something like this:
redirect_to :back, custom_param='foo'

Try this:
# get a URI object for referring url
referrer_url = URI.parse(request.referrer) rescue URI.parse(some_default_url)
# need to have a default in case referrer is not given
# append the query string to the referrer url
referrer_url.query = Rack::Utils.parse_nested_query(referrer_url.query).
# referrer_url.query returns the existing query string => "f=b"
# Rack::Utils.parse_nested_query converts query string to hash => {f: "b"}
merge({cp: 'foo'}).
# merge appends or overwrites the new parameter => {f: "b", cp: :foo'}
to_query
# to_query converts hash back to query string => "f=b&cp=foo"
# redirect to the referrer url with the modified query string
redirect_to referrer_url.to_s
# to_s converts the URI object to url string

You can put it in session and then redirect back
session[:somekey] = value
redirect_to :back

Another approach could be to pass it via "flash" (it goes away automatically after the redirect request):
flash[:somekey] = 'some value'
redirect_to :back
However, as one of my colleagues noted, a better way is probably to return it as a query param, to keep it stateless and distinguish the two URLs. It seems there isn't a nice, built-in Rails way to do that, which makes me wonder what else is wrong with this approach.

Related

rails select query creating alias for attribute name

With the goal of creating a JSON string, the requirement is to use an existing attribute and assign it, in the JSON output, with the attribute name id.
#valids = Destination.limit(10).select(:name, :long_name, :other_code).as_json(except: :id)
except: :id is being invoked to avoid confusion, as other_code attribute is intended to be the id in the generated JSON.
this will then be transformed into valid JSON via
#valids.to_json
how can other_code be output as id ?
You can do this like that with a simple string instead of symbols.
Destination
.limit(10)
.select('name, long_name, other_code as id')
.as_json
Honestly am new to Ruby on rails but very experience with json and frontend application responses
You can try this. if it work, you can now try it with your database responses. Ensure that column id exist in that your database
def your_definition_here
respond_to do |format|
#valids='999'
format.json do
render json: {id: #valids}.to_json
#render json: {id: #valids.id}.to_json
end
end
end

[Ruby on Rails]Redirect to RESTful URL

I am working on a movie rails project and I have to redirect the url to be RESTful, but I have no idea how to make it done. The following information may be useful:
I fail to: GET /movies when selecting a movie rating should redirect to a RESTful route
rake routes:
Prefix Verb URI Pattern Controller#Action
root GET / movies#index
movies GET /movies(.:format) movies#index
POST /movies(.:format) movies#create
new_movie GET /movies/new(.:format) movies#new
edit_movie GET /movies/:id/edit(.:format) movies#edit
movie GET /movies/:id(.:format) movies#show
PATCH /movies/:id(.:format) movies#update
PUT /movies/:id(.:format) movies#update
DELETE /movies/:id(.:format) movies#destroy
The UI of the webpage
Some descriptions of what I have to do: (generally saying if the user intentionally deletes some attributes from the url, I have redirect it to the correct url):
To be RESTful, we want to preserve the property that a URI that results in a sorted/filtered view always contains the corresponding sorting/filtering parameters.
The code I have implemented to do the task:
if !(params.has_key?(:sort_by)) #check the url has this parameter
if session[:sort_by] #has cookie
redirect_to movies_path(:sort_by => session[:sort_by]) #redirect using cookie, not sure need to add :ratings
else
session[:sort_by] = "id" # default sorting
end
end
if !(params.has_key?(:ratings))
if session[:ratings]
redirect_to movies_path(:ratings => session[:ratings]) # error: AbstractController::DoubleRenderError
else
session[:rating] = {"G"=>"1", "PG"=>"1", "PG-13"=>"1", "R"=>"1"}
end
end
:sort_by is the attribute to control how is the movies sorted, e.g. session[:sort_by] = "date" means sorted on the release date.
:ratings is something like: "ratings"=>{"G"=>"1", "PG-13"=>"1", "R"=>"1"}
An example of URL: /movies?ratings%5BG%5D=1&ratings%5BPG%5D=1&ratings%5BPG-13%5D=1&ratings%5BR%5D=1&sort_by=title
if I type something like .../movies, the url should be generated from cookie(if any). But I am having some problems:
for example we check that sort_by is missing, and there is session for sort_by, do we still need to supply session[:ratings] to movies_path()? And what to do if it is the first time I come to this website (no session[:ratings]/session[:sort_by]) but I still need the RESTful URL(all checked boxes are 'clicked' by default)
Some more instructions:
So you should redirect when parameters are missing in URL, instead of in URL + session.
It means that when ‘sort_by’ is not in the URL, but in the session, you should complete this URL with session data, and redirect to the complete URL (so fill in if ‘ratings’ is also missing).
Now what if a parameter is missing in both URL and session? You should rely on some initialization rules. For ‘ratings’, you should check all ratings; and for ‘sort_by’, you can set the keyword to ‘id’, which is how items are sorted by default (the order of movies in the array returned by Movie.all).
Something like this should work
def index
session[:sort_by] = if params[:sort_by].present?
params[:sort_by]
else
session[:sort_by] || 'id'
end
session[:rating] = if params[:rating].present?
params[:rating]
else
session[:rating] || { 'G' => '1', 'PG' => '1', 'PG-13' => '1', 'R' => '1' }
end
if !(params[:sort_by].present? && params[:rating].present?)
redirect_to movies_path(sort_by: session[:sort_by], rating: session[:rating])
return
end
end
First couple lines set up the session to the parameter value if one was passed in, otherwise checks for an existing session value, and then falls back to the default.
Then, we look to see if either the sort_by or the rating parameter were missing, we'll redirect to include both of them from the new values in the session.
I believe this hits all your criteria. The main problem you were having is that as soon as you call redirect_to, it's going to try and redirect, it doesn't like having code (especially other redirect or render calls) after it. So you need to check any conditions you need and then lump it all into one redirect call and then return from the method so it doesn't try to also render.

How to create Post request to Rails API using Postman?

I am new to Postman. I have a Rails server running on the background. I am trying to mock a POST request, but it is not being accepted.
Let's say the model is called manufacturer_organization.rb. Inside, it requires 3 parameters: organization_id (uuid data type), manufacturer_id (integer data type), and account_number (string data type). manufacturer_organization belongs_to organization and it also belongs_to :manufacturer (vice versa; manufacturer and organization has_many manufacturer_organization)
Inside manufacturer_organizations_controller.rb, I have a create method:
def create
#manufacturer_organization = ManufacturerOrganization.new(manufacturer_organization_params)
if #manufacturer_organization.save
puts "success!"
render json: #manufacturer_organization
else
puts "Sorry, something went wrong"
end
end
I can confirm that I have sufficient authorization; when I perform a GET request I got the right JSON response. I am using rails serializer and I have setup serializer for this model as well. Route is also setup using resources :manufacturer_organizations. My gut feeling says the way I am using postman is wrong.
Here is the screenshot of Postman app. I have the right address on address bar, and I am performing a POST request. I have the three params under key-value.
After I Send it, under my Rails Server log I see:
Started POST "/manufacturer_organizations" for 127.0.0.1 at 2017-04-13 16:56:44 -0700
Processing by ManufacturerOrganizationsController#create as */*
Parameters: {"organization_id"=>"fb20ddc9-a3ee-47c3-bdd2-f710541-ff89c", "manufacturer_id"=>"1", "account_number"=>"A rand
om account number test"}
...
  (0.4ms)  BEGIN
   (0.3ms)  ROLLBACK
Sorry, something went wrong
I can do ManufacturerOrganization.new(organization_id: Organization.last.id, manufacturer_id: Manufacturer.last.id, and account_number: "random test account number") just fine inside rails console.
How can I submit a POST request from postman to add a new manufacturer_organization?
Edit:
def manufacturer_organization_params
api_params.permit(:organization_id, :manufacturer_id, :account_number)
end
whereas inside application_controller.rb
def api_params
#api_params ||= ActionController::Parameters.new(ActiveModelSerializers::Deserialization.jsonapi_parse(params))
end
Edit2:
I added error.full_messages and this is what I got:
Manufacturer can't be blank
Organization can't be blank
Account number can't be blank
Why are they blank?
You can pass the data using params or within the body request.
The best way to do this is using the body, because you can send files and the request becomes more clean without the params.
To send data in the body, you must pass the model name and attribute in the "key" field, and the value in the "value" field, like this:
I don't understand what you do to your params. There is a reason the ActiveModelSerializers::Deserialization is namespaced in the "Model" namespace. It shouldn't be used to serialize or de-serialize internet params, but instead it's for serializing/de-serializing model instances.
If parameters arrive in the correct format ActionController::Base from which AplicationController and thus ManufacturerOrganizationsController inherit will de-serialize them for you. The Rails query parameter format looks as follows:
name=something #=> params[:name] = 'something'
names[]=something1&names[]=something2 #=> params[:names] = ['something1', 'something2']
instance[id]=1&instance[name]=foo #=> params[:instance] = {id: '1', name: 'foo'}
This can also be stacked and is used for nested resources by Rails. Example:
instance[title]=some&instance[nested][name]=thing&instance[nested][ids][]=1&instance[nested][ids][]=2
#=> params[:instance] = {title: 'some', nested: {name: 'thing', ids: ['1', '2']}}
Having said that let's get to your example. First of al let us throw away those manual building of params and stick to the convention:
class ManufacturerOrganizationsController
# ...
private
def manufacturer_organization_params
# arriving params should look like this:
#
#=> params = {
# manufacturer_organization: {
# organization_id: 'fb20ddc9-a3ee-47c3-bdd2-f710541-ff89c',
# organization_id: '1',
# account_number: 'A random account number test'
# }
# }
#
# The method #require raises an exception if the provided key
# is not present or has a blank value (with exception of false).
# If the key is found and has a value present than that value is
# returned.
#
params.require(:manufacturer_organization)
.permit(:organization_id, :manufacturer_id, :account_number)
end
end
With that out of the way let's send the correct formatted params:
+--------------------------------------------+---------------------------------------+
| Key | Value |
|--------------------------------------------|---------------------------------------|
| manufacturer_organization[organization_id] | fb20ddc9-a3ee-47c3-bdd2-f710541-ff89c |
| manufacturer_organization[manufacturer_id] | 1 |
| manufacturer_organization[account_number] | A random account number test |
+--------------------------------------------+---------------------------------------+
Those 2 things combined should let you create your resource successfully.
The key thing you should take from this is that params is not a string containing al the params that should be de-serialized. It already should be de-serialized, if it's not than you might have send your parameters wrong.
Ruby on Rails and Postman - Post request.
Hello, this is an example that I developed with Postman and Rails API.
Postman.
I can't add images but this what you have to add in postman Key = Value
Change to Post Request and send.
book[name] = 'Harry Potter'
book[author] = J.K. Rowling
Ruby on Rails 7.
Rails maintains the same code.
def create
#book = Book.new(book_params)
if #book.save
render json: #book, status: :created, location: api_v1_books_url(#book)
else
render json: #book.errors, status: :unprocessable_entity
end
end
def book_params
debugger
params.require(:book).permit(:name, :author, :price)
end
I hope this helps.

How to remove special characters from params hash?

I have one application with the following code:
quantity = 3
unit_types = ['MarineTrac','MotoTrac','MarineTrac']
airtime_plan = 'Monthly Airtime Plan'
url = "http://localhost:3000/home/create_units_from_paypal?quantity=#{quantity}&unit_types=#{unit_types}&airtime_plan=#{airtime_plan}"
begin
resp = Net::HTTP.get(URI.parse(URI.encode(url.strip)))
resp = JSON.parse(resp)
puts "resp is: #{resp}"
true
rescue => error
puts "Error: #{error}"
return nil
end
It sends data to my other application via the URL params query string. This is what the controller method of that other application looks like:
def create_units_from_paypal
quantity = params[:quantity]
unit_types = params[:unit_types]
airtime_plan = params[:airtime_plan]
quantity.times do |index|
Unit.create! unit_type_id: UnitType.find_by_name(unit_types[index]),
airtime_plan_id: AirtimePlan.find_by_name(airtime_plan),
activation_state: ACTIVATION_STATES[:activated]
end
respond_to do |format|
format.json { render :json => {:status => "success"}}
end
end
I get this error:
<h1>
NoMethodError
in HomeController#create_units_from_paypal
</h1>
<pre>undefined method `times' for "3":String</pre>
<p><code>Rails.root: /Users/johnmerlino/Documents/github/my_app</code></p>
I tried using both raw and html_safe on the params[:quantity] and other params, but still I get the error. Note I had to use URI.encode(url) because URI.parse(url) returned bad uri probably because of the array of unit_types.
Change:
quantity.times do |index|
To:
quantity.to_i.times do |index|
The reason you are having this problem is because you are treating the params values as the types that you originally tried to send, but they are actually always going to be strings. Converting back to the expected 'type' solves your problem.
However, you have some more fundamental problems. Firstly, you are trying to send an array by simply formatting it to a string. However, this is not the format that the receiving application expects to translate back to an array. Secondly, there is duplication in your request - you don't need to specify a quantity. The length of the array itself is the quantity. A better method would be to build your url like this:
url = 'http://localhost:3000/home/create_units_from_paypal?'
url << URI.escape("airtime_plan=#{airtime_plan}") << "&"
url << unit_types.map{|ut| URI.escape "unit_types[]=#{ut}" }.join('&')
On the receiving side, you can do this:
def create_units_from_paypal
unit_types = params[:unit_types]
airtime_plan = params[:airtime_plan]
quantity = unit_types.try(:length) || 0
#...

How to chain optional Mongoid criteria in separate statements?

I'm trying to chain criteria based on optional rails
parameters.
I want to be able to simultaneously filter based on selected tags as
well as searching.
Here is the current code that works in all situations:
if params[:tag] and params[:search]
#notes = Note.tagged_with_criteria(params[:tag]).full_text_search(params[:search])
elsif params[:tag]
#notes = Note.tagged_with_criteria(params[:tag])
elsif params[:search]
#notes = Note.full_text_search(params[:search])
end
I tried simply using
#notes = Note.tagged_with_criteria(params[:tag]).full_text_search(params[:search])
without the if statement, but then if only one of the params was
given, then all notes are returned.
Each of the methods (tagged_with_criteria and full_text_search) are
returning Note.criteria if their parameter is nil / empty.
Is there a simpler, more elegant way to chain Mongoid criteria like this?
I'd rather keep tacking on criteria one-by-one instead of having to do
the weird "if params[...] and params[...]" thing..
UPDATE: here are the current methods:
def tagged_with_criteria(_tags)
_tags = [_tags] unless _tags.is_a? Array
if _tags.empty?
criteria
else
criteria.in(:tags => _tags)
end
end
def self.full_text_search(query)
if query
begin
regex = /#{query}/
# supplied string is valid regex (without the forward slashes) - use it as such
criteria.where(:content => regex)
rescue
# not a valid regexp -treat as literal search string
criteria.where(:content => (/#{Regexp.escape(query)}/))
end
else
# show all notes if there's no search parameter
criteria
end
end
In a situation like that, I would modify the scopes to do nothing when passed in blank values.
I think what might be happening is you are getting empty strings from the params hash, which is causing your code to think that something was entered. Try the scopes with these edits.
def tagged_with_criteria(_tags)
_tags = Array.wrap(_tags).reject(&:blank?)
if _tags.empty?
criteria
else
criteria.in(:tags => _tags)
end
end
def self.full_text_search(query)
if query.present?
begin
regex = /#{query}/
# supplied string is valid regex (without the forward slashes) - use it as such
criteria.where(:content => regex)
rescue
# not a valid regexp -treat as literal search string
criteria.where(:content => (/#{Regexp.escape(query)}/))
end
else
# show all notes if there's no search parameter
criteria
end
end

Resources