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
Related
I'm very much a beginner when it comes to database relationships hence what I suspect is a basic question! I have two database tables as follows:
Projects
id
company_id
name
etc...
rfis
id
project_id (foreign key is id on the Projects table above)
Number (this is the column I need help with - more below)
question
The relationships at the Model level for these tables are as follows:
Project
public function rfi()
{
return $this->hasMany('App\Rfi');
}
RFI
public function project()
{
return $this->belongsTo('App\Project');
}
What I'm trying to achieve
In the RFI table I need a system generated number or essentially a count of RFI's. Where I'm finding the difficulty is that I need the RFI number/count to start again for each project. To clarify, please see the RFI table below which I have manually created with the the 'number' how I would like it displayed (notice it resets for each new project and the count starts from there).
Any assistance would be much appreciated!
Todd
So the number field depends on the number of project_id in the RFI table. It is exactly the number of rows with project_id plus one.
So when you want to insert a new row, you calculate number based on project_id and assign it.
RFI::create([
'project_id' => $project_id,
'number' => RFI::where('project_id', $project_id)->count() + 1,
...
]);
What I understood is that you want to set the value of the "number" field to "1" if it's a new project and "increment" if it's an existing project. And you want to automate this without checking for it every time you save a new row for "RFI" table.
What you need is a mutator. It's basically a method that you will write inside the desired Model class and there you will write your own logic for saving data. Laravel will run that function automatically every time you save something. Here you will learn more about mutators.
Use this method inside the "RFI" model class.
public function setNumberAttribute($value)
{
if(this is new project)
$this->attributes['number'] = 1;
else
$this->attributes['number']++;
}
Bonus topic: while talking about mutators, there's also another type of method called accessor. It does the same thing as mutators do, but just the opposite. Mutators get called while saving data, accessors get called while fetching data.
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)
I have a model called "blog", which has several columns, including one called "token".
I want to retrieve a row based on the token that's in a url - for instance, if the user goes to /blog/post1, I want to retrieve the row where token = post1
In my app setup I'm doing:
get '/blog/:id' do
#postID = params[:id]
#thePost = Blog.where(token: #postID)
render 'blog/index'
end
When I try to access <%= #thePost %> in my .erb file, I get:
#<Sequel::Mysql2::Dataset:0x007fdec1777318>
How do I access the actual data from the row here?
You are returning a relation, what you want to return is an actual record. To do this, use first at the end of your where call.
Blog.where(token: #postID).first
Blog.where(token: #postID) returns a list with all matches - even if the list contains only one elemen. OP is using the Sequel ORM instead of ActiveRecord (Hint is the return type Sequel::Mysql2::Dataset), therefore I would suggest to use first (or first! depending on your usecase) instead of where:
#thePost = Blog.first(token: #postID)
From the docs:
An alias for calling first on the model's dataset, but with optimized handling of the single argument case.
I am creating an auction house similar to eBay. My question is with my bids resource. It will keep track of all of the bids that are placed. However I MUST ensure that every new bid on an item, is higher than the current bid, otherwise that would defeat the purpose of an auction.
The way I currently want to do this is to create a transaction inside the bids controller, that would check whether or not the amount being bid for an item, is greater than the max of the other bids for the same item.
def create
bid.transaction
#bid = Bid.new(params[:bid])
#bid.user = current_user
#bid.item = current_item
# DO STUFF TO CHECK ITS GREATER THAN MAX OF BIDS FOR CURRENT_ITEM
# ON ERROR, ROLLBACK TRANSACTION AND THROW ERROR
end
end
I would definitely handle this in the model. Create a custom validation such as:
#Bid Model
validate :bid_is_higher_than_current_highest
private
def bid_is_higher_than_current_highest
bid > item.current_highest_bid
end
Something like that.
First off make sure you're using the InnoDB table type as MyISAM does not support transactions.
But you're basically right, you just want to run a query inside your transaction to determine the maximum bid:
max_bid_amount = Bid.where(:id => item.id).maximum(:bid_amount)
if #bid.bid_amount > max_bid_amount
# proceed with bid placement
else
# do something, return some flag, nil or whatever
end
Then check the value and proceed accordingly. I would think you would not want to raise an exception for flow control purposes.
I also recommend that you move this logic outside of the controller and either into the Model or some other management layer, maybe have a generic Ruby class like BidManager which contains the flow logic for bid placement.
I am working on RoR 3.x with MySQL as backend.
Is there any way to modify the existing id (autogenerated with migration) in a way that can generate particular user defined pattern.
For e.g : "Products Table" should have values in "id" field like "P01", "P02" and so on, where P can be specified by the user, and 01,02 are autogenerated.
Thanks in advance!
The 'regular' IDs (1, 2, 3, ..., n) in this case aren't generated by rails but by MySQL (using AUTO_INCREMENT). So, if you want to go with auto-generated, auto-incrementing IDs, I would suggest not messing with this. What you could do, and what I would suggest, is creating an additional column and then populating that using a callback on your model.
Example:
class Product < ActiveRecord::Base
attr_accessor :user_supplied_prefix
after_create :generate_user_supplied_id
private
def generate_user_supplied_id
update_attribute(:user_supplied_id, "#{self.user_supplied_prefix}#{self.id}")
end
end
The downside of this approach is that Product.find(user_supplied_id) won't work. Fortunately, Product.find_by_user_supplied_id(user_supplied_id) will.