Latest from the Rocketship
We like writing about our personal experiences, our challenges and our take on programming and management. Enjoy!
Create factory with an uploaded file in Rails rspec
To create a factory with an uploaded file in Rails rspec, needs to be included ActionDispatch::TestProcess module in the rails_helper.rb file to use the #fixture_file_upload method in the factories.
# spec/rails_helper.rb include ActionDispatch::TestProcess
In a factory, when setting the attribute value, use the method #fixture_file_upload, specifying the path and file type.
# spec/factories/import_file.rb FactoryBot.define do factory :import_file, class: ImportFile do data { fixture_file_upload 'spec/fixtures/test_file.pdf', 'application/pdf' } end end
Get most performant function
Let's say you need to determine which function is execute faster.
Write a function that take array of functions and iterates each of them a certain number of times.
Will use the difference in performance.now() values before and after to get the total time in milliseconds each iteration running.
Play with iterations argument to get more or less reliable results.
const mostPerformantFunction = (fns, iterations = 10000) => { const times = fns.map(fn => { const before = performance.now(); for (let i = 0; i < iterations; i++) fn(); return performance.now() - before; }); console.log(times); return times.indexOf(Math.min(...times)); };
mostPerformantFunction([ () => { [1, 2, 3, 4, 5, 6, 7, 8, 9, '10'].every(el => typeof el === 'number'); }, () => { [1, '2', 3, 4, 5, 6, 7, 8, 9, 10].every(el => typeof el === 'number'); } ]); // 1
How to download files with Axios
A simple example using the Blob() constructor:
export function someFunction(values) { return (dispatch) => { ... const method = 'GET'; const url = 'http://go.api/download_file'; ... axios .request({ url, method, responseType: 'blob', //important }) .then(({ data }) => { const downloadUrl = window.URL.createObjectURL(new Blob([data])); const link = document.createElement('a'); link.href = downloadUrl; link.setAttribute('download', 'file.zip'); //any other extension document.body.appendChild(link); link.click(); link.remove(); }); }; }
How to conditionally render template in Grape resources?
Suppose you need to conditionally render some template in a given endpoint of a Grape resource. There is a env data in Grape::API class that represents Rack environment of the request. env is just a simple Ruby hash and we can pass the template name to it's api.tilt.template key to render that template:
env['api.tilt.template'] = 'foo/bar.json'
Then let's define a render method in Base resourсe:
class Base < Grape::API def self.inherited(subclass) super subclass.instance_eval do helpers do def render(template_name) env['api.tilt.template'] = template_name end end end end end
Now we can use it in the following way:
class ContactsResource < Base desc 'Create contact', http_codes: [[201, 'Created']] post '/contacts' do contact = Contact.new(params[:contact]) if contact.save render 'v1/contacts/show.json' else error!({ errors: contact.errors.full_messages }, 422) end end end
Append string to a route with a slash operator
If you need to append string to some route to build a path name you can use few ways:
Rails.root + 'foo/bar' [Rails.root, 'foo/bar'].join('/') "#{Rails.root}/foo/bar"
But also there is a Pathname#/ method, so you can append string to route using a slash:
Rails.root/'foo/bar' # => #<Pathname:/Users/alex/myproject/foo/bar>
Looks more readable!
How to add a line break to PostgreSQL?
You have to insert some data into your PostgreSQL table that has line break. As a result, the cell will look like this:
First line Second line
To use "escape sequences" in a string literal you need to use an "extended" constant. You can specify the escape character by prefixing the letter E:
UPDATE posts SET body = E'First Line\nSecond line.' WHERE id = 2701;
Recompose withContext and getContext. Simple example
Very often for nested components you need to transfer some props of the parent. For example size. So, we have the Card component. It contains a Button component.
// App.js <Card size="sm"> {/* ... */} <div> {/* ... */} <Button size="sm" onClick={action}>Action</Button> </div> </Card>
The size for both components is set by the "size" parameter. In the example above, the parameter passed is indicated for both components. In order not to specify the size for the Button each time, you can use the Context to use the one specified for the Card. If you use recompose, it can be super easy:
// Card.js import { getContext } from 'recompose'; // ... export default withContext( { size: PropTypes.oneOf(['sm', 'md', 'lg']) }, ({ size }) => ({ size }), )(Card); // App.js import Button from './Button'; // ... const EnhancedButton = getContext({ size: PropTypes.oneOf(['sm', 'md', 'lg']) })(Button);
Live example
AND & OR Operators Precedence
Are you still sure that && and and is the same operators? Look at this:
a = true && false a => false
a = true and false a => true
The same situation could be reproduced for || and or. Why? The answer lies in Ruby Operator Precedence.
The first example can be represented as:
a = (true && false)
Second:
(a = true) and false
Thanks to Igor Alexandrov
Sort lines in the vim editor
Often when writing code, you need to sort the lines in alphabetical order. For example, in javascript, when importing a large number of modules, it is good practice to organize them alphabetically. Users of the vim editor can do this very simply. It is enough to select in the visual mode all the lines that need to be sorted and enter the command :sort. All rows are sorted!
Custom onChange in React Final Form
Let's take a case when we need to call our own function to change a state of a specific field in a form (our react final form).
Here is a way to do the exact that:
You should pass your function as a parameter and after that just call it inside of the onChange method
Example:
const FormGroupAdapter = ({ input, inputOnChange }) => { const inputProps = { ...input, onChange: e => { input.onChange(e); inputOnChange && inputOnChange(e); } }; return <input {...inputProps} />; }; const handleChange = event => { console.log("!!!", event.target.value); }; const App = () => ( <Form ... render={({ handleSubmit, reset, submitting, pristine, values }) => ( <form onSubmit={handleSubmit}> <div> <label>some label</label> <Field name="someField" component={FormGroupAdapter} inputOnChange={handleChange} /> </div> ... </form> )} /> );
Live example
Elixir code formatting in IDE (with Atom set up example)
Today I learned that Elixir has a great feature that allows you to format your code.
Here are a few reasons you may want to do that (borrowed from The Go Blog):
-
easier to write: never worry about minor formatting concerns,
-
easier to read: when all code looks the same you need not mentally convert others' formatting style into something you can understand.
-
easier to maintain: diffs show only the real changes.
-
uncontroversial: never have a debate about spacing or brace position ever again
In fact, you actually want to format your Elixir code as you make it, meaning there is no need to format all of your project's code every time.
The following bash command does it well on a single file:
cd $projectPath && mix format $filePath
Where: $projectPath - full path to your project's root directory; $filePath - full path to a file you're saving
My IDE of choice happened to be Atom and I'll talk briefly on setting it up.
The Process Palette package so far is the best for this task.
My Shell Command field (with variables) in Process Palette looks the following cd {projectPath} && mix format {fileAbsPath}
How to display numbers with currency formatting in JS?
Use Intl.NumberFormat to enable country / currency sensitive formatting.
const toCurrency = (n, curr, LanguageFormat = undefined) => Intl.NumberFormat(LanguageFormat, { style: 'currency', currency: curr }).format(n);
toCurrency(123456.789, 'EUR'); // €123,456.79 | currency: Euro | currencyLangFormat: Local toCurrency(123456.789, 'RUB'); // RUB 123,456.79 | currency: Ruble | currencyLangFormat: Local toCurrency(123456.789, 'RUB', 'Ru-ru') // 123 456,79 ₽ | currency: Ruble | currencyLangFormat: Russian toCurrency(123456.789, 'USD', 'en-us'); // $123,456.79 | currency: US Dollar | currencyLangFormat: English (United States) toCurrency(123456.789, 'USD', 'fa'); // ۱۲۳٬۴۵۶٫۷۹ $ | currency: US Dollar | currencyLangFormat: Farsi toCurrency(322342436423.2435, 'JPY'); // ¥322,342,436,423 | currency: Japanese Yen | currencyLangFormat: Local toCurrency(322342436423.2435, 'JPY', 'fi'); // 322 342 436 423 ¥ | currency: Japanese Yen | currencyLangFormat: Finnish
Safe Navigation vs Try in Rails (Part 2: Performance)
This Note is an extension of Safe Navigation vs Try in Rails (Part 1: Basic Differences)
Method try() comes from Active Support component of Ruby on Rails. Safe Navigation Operator is Ruby native feature.
Let's check performance!
require 'benchmark' class Foo attr_accessor :name end foo = Foo.new bar = nil Benchmark.bm(35) do |x| x.report('Successful access: try(...): ') { 1_000_000.times { foo.try(:name) } } x.report('Successful access: &.: ') { 1_000_000.times { foo&.name } } x.report('Successful access: control sample: ') { 1_000_000.times { foo.name } } x.report('Failed access: try(...): ') { 1_000_000.times { bar.try(:nonexistent) } } x.report('Failed access: safe navigation: ') { 1_000_000.times { bar&.nonexistent } } end;nil
user system total real Successful access: try(...): 0.498216 0.005748 0.503964 ( 0.530010) Successful access: &.: 0.062146 0.000943 0.063089 ( 0.069714) Successful access: control sample: 0.062411 0.001098 0.063509 ( 0.069603) Failed access: try(...): 0.172535 0.004374 0.176909 ( 0.194386) Failed access: safe navigation: 0.054141 0.001029 0.055170 ( 0.065502)
Safe navigation is about 7 times faster than method try() for successful navigation and 3 times faster for unsuccessful.
Safe Navigation vs Try in Rails (Part 1: Basic Differences)
There are some ways of preventing errors like undefined method for nil:NilClass.
-
Rails Method
try(...) -
Safe Navigation Operator (
&.) -
Logical operator
&&(AND)
Here is how these options look like:
user.try(:company).try(:name)
user&.company&.name
user && user.company && user.company.name
But there are some differences.
1. If model User hasn't relation compppany (it may be just a typo or renamed model relation/attribute):
user.try(:compppany).try(:name) => nil
You will receive nil and never been know about this typo.
user&.compppany&.name => NoMethodError: undefined method `compppany' for #<User:0x000000123456789>
and
user && user.compppany && user.compppany.name => NoMethodError: undefined method `compppany' for #<User:0x000000123456789>
Looks better!
2. If model User has relation company, but company is false. User.new(company: false):
user.try(:company).try(:name) => nil
user&.company&.name => NoMethodError: undefined method `name' for false:FalseClass
Safe Navigation recognized false. Awesome!
user && user.company && user.company.name => false
Hmmm, it does not look like we want.
3. Performance
Read the second part Safe Navigation vs Try in Rails (Part 2: Performance)
Force Downloading of File instead of Opening in Browser
When you go through the link, some files will be opened in the browser. Such behavior is typical for some content types (e.g., images, pdf, etc.)
However, you can force file downloading instead of opening when an user clicks on the link though.
1st way (frontend):
HTML attribute download allows you to do this.
<a href="/public/report.pdf" download="stat_report">
If the value of the attribute is omitted, the original filename would be used.
However, be careful. This attribute isn’t supported in some old browsers without HTML5 support.
Renaming does not work if the given file stored on another host.
2nd way (backend):
You can set HTTP header Content-disposition.
for Nginx:
location ~* /public/(.+\.pdf)$ { add_header Content-disposition "attachment; filename=$1"; }
for Apache:
<IfModule mod_headers.c> <FilesMatch "\.(?i:pdf)$"> ForceType application/octet-stream Header set Content-Disposition "attachment" </FilesMatch> </IfModule>
How to delete polymorphic models cascade
If you use a polymorphic model in your Rails application, like in example
class Trade < ActiveRecord::Base has_many :gl_entries, as: :source, dependent: :destroy end class GlEntry < ActiveRecord::Base belongs_to :source, polymorphic: true end
You will not be able to add the usual foreign keys for cascading delete records. But this can be implemented using a database.
To do this, you need to write a trigger in the database that will run the delete function for each record.
CREATE FUNCTION deleteGlEntriesOfTrade() RETURNS TRIGGER SET SCHEMA 'public' LANGUAGE plpgsql AS $$ BEGIN DELETE FROM gl_entries WHERE source_id = OLD.id AND source_type = 'Trade'; RETURN OLD; END; $$; CREATE TRIGGER deleteTradesGlEntriesTrigger BEFORE DELETE ON trades FOR EACH ROW EXECUTE PROCEDURE deleteGlEntriesOfTrade();
Create a migration and use :)
Sidekiq Stats in Rails
If you use Sidekiq in your Rails project, you can watch tasks statistics through the web interface. Usually, you can find it here: https://yourdomain.com/sidekiq (but in your project path may be different).
If you don't have access there, you can get the same data in Rails console.
To get statistics (number of tasks) by each queue:
Sidekiq::Stats.new.queues => {"local_cache"=>0, "default"=>0, "ts_delta"=>0, "mailchimp"=>0, "recorder"=>0}
Global statistics are available this way:
Sidekiq::Stats.new.fetch_stats! => {:processed=>61390, :failed=>3220, :scheduled_size=>0, :retry_size=>0, :dead_size=>4, :processes_size=>1, :default_queue_latency=>0, :workers_size=>0, :enqueued=>0}
The same stats are available separately:
stats = Sidekiq::Stats.new stats.processed # number of processed tasks stats.failed # number of failed tasks stats.enqueued # number of enqueued tasks
and etc.
Also Sidekiq::Stats allows to look historical data. You can specify period. Something like:
s = Sidekiq::Stats::History.new(2, Date.parse('2019-02-05'))
-
first argument: number of days,
-
second argument: date until which return stats (default value is today and can be omitted)
s.processed => {"2019-02-05"=>0, "2019-02-04"=>0} s.failed => {"2019-02-05"=>0, "2019-02-04"=>0}
Keep clean your git repos!
Many developers don't keep their local repositories clean. There is a way how to automate it though. Let's look at a few useful commands:
To clean refs to nonexistent branches in the remote:
$ git fetch --prune
--prune before fetching, remove any remote-tracking references that no longer exist on the remote.
To estimate how many branches merged into dev:
$ git branch --merged dev | wc -l
--merged option can filter list to branches that you have merged into the given branch. Squash and rebase merges usually aren't detected by --merged.
List of branches merged into dev:
$ git branch --merged dev
List of remote branches merged into dev:
$ git branch --merged dev --remote
If you are courageous then:
$ git branch --merged dev | egrep -v "(^\*|master|dev)" | xargs git branch -d
It removes all local branches that merged into dev (except dev and master).
This is a potentially damaging operation. It can delete branches actually needed.
So if you use the different approach to work with Git, you could remove some of branches manually instead. I hope you do not store all old branches, do you?
Getting rid of inefficient constantize
Trying to improve performance of one controller I've found the following:
def application_klass @application_klass ||= "application/#{params[:type]}".classify.constantize end
There are Application::Rental and Application::Bridge models in our rails app, so the method above was used in two places:
-
application_klass.to_s– to get the model name as a string -
application_klass.model_name.human– to get a class name without module prefix
I've refactored method in the following way:
def application_klass @application_klass ||= "application/#{params[:type]}".classify end
And it's occurrences now looks like this:
-
application_klass– just call this method to get a model name -
application_klass.demodulize– usingdemodulizeto split a string with::
I've got rid of unnecessary constantize method, which is quite inefficient: just imagine that your application tries to find a constant in your project with the name specified in the string. See the benchmarks below to evaluate performance gains:
counter = 100_000 type = 'Rental' Benchmark.bm(30) do |x| x.report('demodulize: ') { counter.times { "application/#{type}".classify.demodulize } } x.report('constantize.model_name.human: ') { counter.times { "application/#{type}".classify.constantize.model_name.human } } end user system total real demodulize: 3.560000 0.760000 4.320000 ( 4.381891) constantize.model_name.human: 8.500000 0.070000 8.570000 ( 8.601007)
Use hash or case-statement in Ruby?
Often, when we need to get a value based on the other one, we're using a case-statement. Like this
def realizing_trade_type(realizable_trade_type) case realizable_trade_type when 'buy' 'sell' when 'short' 'cover' when 'buy_contract' 'sell_contract' when 'short_contract' 'cover_contract' end end
But, if the conditions and the results are simple values, why don't we use hash for this? We can :)
REALIZING_TRADE_TYPES = { 'buy' => 'sell', 'short' => 'cover', 'buy_contract' => 'sell_contract', 'short_contract' => 'cover_contract' }.freeze
Here is the benchmark of both options, executed 10000000 times. It shows that a hash is faster in times for such the kind of usage.
>> require 'benchmark' true >> Benchmark.bm(15) do |x| x.report('hash') { 10_000_000.times { REALIZING_TRADE_TYPES['buy'] } } x.report('case-statement') { 10_000_000.times { realizing_trade_type 'buy' } } x.report('empty') { 10_000_000.times {} } end user system total real hash 0.990423 0.003412 0.993835 ( 1.057612) case-statement 1.752263 0.004531 1.756794 ( 1.762030) empty 0.380810 0.000728 0.381538 ( 0.382153)
So, it's better to use a hash when you are just retrieving some values (like in the example above). If there is additional logic to execute, a case-statement is still a way to go.