Passing parameters from form to controller using RoR - html

I am new to RoR development and am a little confused about how parameters are passed from a HTML view to the controller. I have seen a few examples online which use a private method like this:
private
def message_params
params.require(:message).permit(:content)
end
I have been looking for some clarification online as to what this method does and how it works, but I only encounter posts/articles which use the method rather than explain what it does.
I was hoping someone could explain how the method takes(/filters?) values passed via the form via a POST request, what the require and permit keywords mean and how would i change this method to fit my own use.
For example if i needed to get data about a new book would i do this:
private
def book_params
params.require(:book_name).require(:ISBN).require(:Author).permit(:Illustrator)
end
Would the above be valid given that my book object has those fields?
Any clarification would be appreciated.
Thank you.

here is some info (I'm using your sample model Book and BookController), that probably can help you more understand
when you submit form, rails automatically called create method, inside create method you will see Book.new(book_params), book_params will call private method and will check which field allowed, if there is another field that submitted but not listed inside your permit block then it will be not passed along to save command
class BooksController < ApplicationController
def create
#book = Book.new(book_params)
if #book.save
flash[:success] = 'Data save successfully'
redirect_to books_path
else
render :new
end
end
private
def book_params
params.require(:book).permit(
:book_name,
:isbn,
:author,
:illustrator)
end
end

This kind of function is used to whitelist params - ie say you have a message model, and through the controller actions you should only be able to change the content. Maybe there is also an author field - but even if someone were to pass that through the form, you would not want to update it.
params.require(:message)
Will return to you params[:message]. permit means you are allowing only the content field through.
See: http://edgeguides.rubyonrails.org/action_controller_overview.html#strong-parameters
I would need to see your model setup, but I would assume given a book model you'd want something more akin to:
params.require(:book).permit(:illustrator, :author, :isbn)

Related

Generating an auto incrementing number in rails

I am very new to rails and was wondering if someone might be able to help me.
I need to generate and save an auto incrementing number for an invoicing. Ive already created the field 'invoicenum:integer' in my billing_history table.
I was wondering how I can do this from the controller ? This is the entry point where I was wanting to put it. Im not sure how I would write the function to create this incrementing number... Do i write it inside this function or do i create another function outside of this and just call it ?
transaction.company.billing_history.create!(
reference: transaction.description,
amount: transaction.amount,
plan: transaction.plan,
status: 'success',
invoicenum:
)
it's more preferable to make your controller slim so for a code like this its better to be on the model
lets say you have
BillingHistory.rb
you could set a callback to generate the invoice number like this
class BillingHistory < ApplicationRecord
before_create :generate_invoice_number
private
def generate_invoice_number
# logic for generating invoice number
# adjust accordingly to your needs
self.invoicenum = BillingHistory.maximum(:invoicenum).next
end
end
this will assign the value of BillingHistory.invoicenum before validated

Need to check whether email exists and then update record if it does. Rails

I am just trying to update certain attributes of a record based on whether the email address exists or not.
Controller:
def update
#contact = Contact.new(contact_params)
if #contact.update then
redirect_to :root, notice: 'yes was successfully updated.'
else
render "new"
end
render "show"
end
Model:
class Contact < ApplicationRecord
has_attached_file :image, styles: {large: "600x600>", medium: "300x300>", thumb: "150x150#"}
validates_attachment_content_type :image, content_type: /\Aimage\/.*\z/
#validates :email, uniqueness: true
validates :email, presence: true
end }
Definitely know there's a lot wrong with this and would kindly like some help.
Thanks!
Definitely, there are many things to improve here, first let me explicitly answer your question:
validates: email, uniqueness: true
By adding that validation in your contact model, the update method will return false so the email will not be updated. You can also ignore case_sensitivity by adding case_sensitive: false to the validation.
You should keep in mind that this validation does not guarantee uniqueness if you have multiple servers/server processes (e.g. running Phusion Passenger, multiple Mongrels, etc) or a multi-threaded server. Please check this answer for an extended explanation.
However, that will not work on the code you paste above, let me explain why:
1) The update method requires passing 1 argument, so your code will throw an ArgumentError there.
2) render appears more than one time in the same method: This will throw you the following error
Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like "redirect_to(...) and return".
You will need to refactor your code there.
For redirect_to: root, make sure to configure to root route first.
3) This line Contact.new(contact_params) does not return an existing record. The new method creates an object instance, so you would not be updating anything there.
A possible solution for your method could be:
helper_method :contact
def update
if contact.update(contact_params)
flash[:success] = "Contact updated"
redirect_to :root
else
render :edit
end
end
private
def contact
#contact ||= Contact.find(params[:id])
end
Hope it helps.

How to automatically save data from API - Ruby on Rails

I have searched all over the internet, however, I cannot seem to get a clear answer on this issue. I am using Block.io API to add Bitcoin payments to my app. I receive a JSON hash which includes a new Bitcoin address for each payment, I can extract the bitcoin address, but I need it to save to my database automatically, when a user accesses a specific page the address will also be generated on that page. I am using Postgresql
The JSON looks like this:
{"status"=>"success", "data"=>{"network"=>"BTCTEST", "address"=>"2MstFNxtnp3pLLuXUK4Gra5dMcaz132d4dt", "available_balance"=>"0.01000000", "pending_received_balance"=>"0.00000000"}}
I have a controller which calls the API to generate the address:
class PaymentsController < ApplicationController
def index
#new_address = BlockIo.get_new_address
end
end
And the bitcoin address is displayed using:
<%= #new_address["data"]["address"] %>
I am thinking of creating a new function that will save the bitcoin address to the database and map the route to execute this function upon accessing the specific page, something like:
Controller:
class PaymentsController < ApplicationController
def create
#new_address = BlockIo.get_new_address
## I need assistance with the rest to auto save
end
end
routes:
match '/save_btc' => 'payments#create', via: [:get, :post]
when someone opens domain.com/save_btc the bitcoin address needs to be automatically saved to the database.
I have already generated the following migration
rails g model Payment bitcoin:string
Any comments or assistance will be greatly appreciated.
It looks like BlockIo is already parsing the JSON string for you and returning a regular Ruby hash.
I would try something like this:
new_address = BlockIo.get_new_address
Payment.create( bitcoin: new_address['data']['address'] )
You'll probably want to check the status of the response new_address['status'] and make sure that the address is present before saving. But the code above should get you started.
You'll probably want to do a redirect or something like head :ok after the payment is created.
Note: you do not need to use the # for the variable name. That is usually only used when you're passing that info to a view.

How to perform user input in rails

I've been struggling for a while on this (been reading a lot of the ruby on rail guides to try and understand this), but I'm not sure how user inputs work.
I am trying to search for a restaurant in my database with a list of fields the user specifies (cuisine, zipcode, review score). I have created a html.erb page that has the options for all of these.
Here is my controller.
class WelcomeController < ApplicationController
def home
#my_search = Restaurant.joins(:inspection).where(cuisine: c, zipcode: z, totalscore: 1..h)
end
My models for restaurant and inspection also have relations between them (the foreign keys).
How would you go about letting the user give inputs for c (cuisine), z (zipcode) and 1..h (score range)?
I know that people have answered this question in the past, but I think I need a concrete example to actually understand how to do this. As in, what would you put in the html.erb code so that when an option is selected, that value is passed to the method?
Thank you
First you need to create a form in the view. The simplest way to do this is with form_tag:
<%= form_tag(home_path) do %>
<%= text_field_tag 'cuisine' %>
...other inputs
<% end %>
Next, make sure you have a route defined for your controller action in config/routes.rb
post 'home' => 'welcome#home'
Most likely your routes will look different but this is the bare minimum you need.
And in your controller you can access the submitted data using the params object
class WelcomeController < ApplicationController
def home
#restaurants = Restaurant.joins(:inspection).where(
cuisine: params[:cuisine],
# ...other params
)
end
end

Rails Database Query

I am trying to gather information from a database and then pass that information on to my view via flash. Unfortunately the information is formatting in an ActiveRecord::Relation and not in any format that I can read.
Controller Query
#message = Message.where(:all).limit(4).order(id: :desc).only(:order,:where)
flash[:response] = #message
redirect_to (:back)
If I do something like
#message = Message.where(:all).limit(4).order(id: :desc).only(:order,:where)
flash[:response] = #message.first.mess
redirect_to (:back)
To try and get the first returned value in the mess column, I get an undefined method error. I have been trying to find a tutorial that tells me how to take information once my query has been run but I have not had much luck with Rail's tutorials as of late. I appreciate any help that you guys can give. After I do this I am going to try to format the 4 different results on the view side.
List of messages:
#messages = Message.order(id: :desc).limit(4)
This: only(:order,:where) cancels your limit(4) (why?)
#messages is now an activerecord association, not suitable to output.... So, if you have 4 messages top you can do:
if #messages.any? # maybe no messages come out
flash[:response] = #messages.map(&:mess).join('<br>') # add an html newline between them
end
redirect_to :back