-bash> gem push mygem-1.2.3.gem
Enter your RubyGems.org credentials.
Don't have an account yet? Create one at http://rubygems.org/sign_up
Email: ^CERROR: Interrupted
If you want to use gem commands from the command line, you'll need a ~/.gem/credentials file, which you can generate using the following command:
bash
-bash> curl -u bart https://rubygems.org/api/v1/api_key.yaml > ~/.gem/credentials
Enter host password for user 'bart':
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 56 0 56 0 0 53 0 --:--:-- 0:00:01 --:--:-- 495
Note that you can only push a single gem version once; if you update your gem in any way, and want to update rubygems.org, you'll have to increment the version number, build the gem again, git add new/changed files, remove the old version from git tracking, and then push the new version.
On the other hand there is an argument for putting the protection into the model rather than controller:
Protecting attributes from within controllers sounds like a setup to have multiple points of fault. If I have more than one controller making saves/updates on the same model (ignoring a debate over if that is good design), then I have to remember to protect attributes in multiple controllers. If I handle mass assignment from the model, there's a single, definitive barrier between submitted params and persistence, irrespective of where that data originated. -- @Eleo
@Eleo exactly. That's what I tried to say [to] dhh in my gist. Controller has nothing to do with unintended params. It doesnt filter. It handles, manages, controls business logic.
IMO You should write your controllers way described below:
1) have all critical fields protected/updateable - accessible
2) control saving new record in controller using role checks, dependencies and abilities. Not just by filtering :user_id
3) Never simplify business logic for "update". People got role checks in "create" but trying to manage just "update_attributes" in edit and that's why this has happened. If you check role - check it on create and on update.
DHH advises against putting mass-assignment protection into the model:
The basic idea is to move mass-assignment protection out of the model and into the controller where it belongs.
The whole point of the controller is to control the flow between user and application, including authentication, authorization, and as part of that access control.
This new approach is an extraction of the slice pattern and we're calling the plugin for it strong_parameters (already available as a gem as well).
I decided against the Endless Page feature, and instead slightly adapted this RailsCast's code to provide a "Show more results" link, which would append results in much the same manner, but instead by click rather than reached-bottom-of-page detection.
The main change is the addition of the prepend line in products.js.coffee:
products.js.coffee
jQuery ->
if $('.pagination').length
$('#append_and_paginate').prepend('<a id="append_more_results" href="javascript:void(0);">Show more products</a>');
$('#append_more_results').click ->
url = $('.pagination .next_page').attr('href')
if url
$('.pagination').text('Fetching more products...')
$.getScript(url)
Regarding the view, I only added a surrounding div:
And in products/index.js.erb I just changed the remove line to $('#append_and_paginate').remove(); so that both the "Show more results" link and pagination is removed when no more results are available.
Of course some css had to be added to make things look nice.
But anyway, the cool thing about this approach is that the "Show more products" link is only added by Javascript (hence only if Javascript is present and enabled). The click handler is bound to the DOM element with id="append_more_results", which is the id of the link tag that is prepended.
I have a respond_to block in the index action of my controller, so I had to add format.js to render the RJS template associated with this action (i.e. /app/views/products/index.js.erb):
@Alexander Zubkov, thanks a lot for posting your module! I tried it out and it works! My preference though, is not for max+1 but max of a particular set +1. So I used your module as inspiration, but ended up doing this manually as follows.
This works just as I want, but I wonder if there's a way to make this into a module! You'd have to be able to tell the callback method (set_position) which column (in this case "edition_id") to use in the where clause. I'm too new to RoR to be able to figure this out. Any suggestions?
Let's say you wanted to add sort order to the results in my comment above, then you could do this:
models/project.rb
defself.search(search)
if search
where('name LIKE ?', "%#{search}%").order('created_at DESC')
else
order('created_at DESC') # note: default is all, just sortedendend
And then you could refactor like this:
models/project.rb
defself.search(search)
arel = order('created_at DESC') # note: default is all, just sorted
arel = arel.where('name LIKE ?', "%#{search}%").order('created_at DESC') if search.present?
arel
end
And if you also wanted to search description you might do this:
models/project.rb
defself.search(search)
arel = order('created_at DESC') # note: default is all, just sorted
arel = arel.where('name LIKE ? OR description LIKE ?', "%#{search}%", "%#{search}%").order('created_at DESC') if search.present?
arel
end
Next, change your controller to pass the whole params rather than just params[:search]):
projects_controller.rb
defindex@projects = Project.search(params)
end
Then update your search method accordingly:
models/project.rb
defself.search(params)
arel = order('created_at DESC') # note: default is all, just sorted
arel = arel.where('name LIKE ? OR description LIKE ?', "%#{params[:search]}%", "%#{params[:search]}%").order('created_at DESC') if params[:search].present?
arel
end
Why do all this? Because if you had more fields in your search view, you could easily search them too! For instance, let's say you change the above view to also include min price and max price:
defself.search(params)
arel = order('created_at DESC') # note: default is all, just sorted
arel = arel.where('name LIKE ? OR description LIKE ?', "%#{params[:search]}%", "%#{params[:search]}%").order('created_at DESC') if params[:search].present?
arel = arel.where('price >= ?', params[:min_price]) if params[:min_price].present?
arel = arel.where('price <= ?', params[:max_price]) if params[:max_price].present?
arel
end
And for style you could change your view to use search_field_tag, size, and placeholder:
A common misconception is that
a ||= b
is equivalent toa = a || b
, but it actually behaves likea || a = b
.Good point (re: remember me from multiple machines).
GitHub stopped building gems in October of 2009. They suggest RubyGems.org.
See RubyGems' docs on Distributing Gems
Create an account: http://rubygems.org/sign_up
If you want to use gem commands from the command line, you'll need a
~/.gem/credentials
file, which you can generate using the following command:Try again:
Note that you can only push a single gem version once; if you update your gem in any way, and want to update rubygems.org, you'll have to increment the version number, build the gem again, git add new/changed files, remove the old version from git tracking, and then push the new version.
On the other hand there is an argument for putting the protection into the model rather than controller:
See: Mass assignment vulnerability - how to force dev. define attr_accesible?
Heads-up! New approach!
DHH advises against putting mass-assignment protection into the model:
See: http://weblog.rubyonrails.org/2012/3/21/strong-parameters/
p.s. Here's the blog of the Russian programmer, Egor Homakov, who cleverly brought this vulnerability to everyone's attention. BTW, the rails team supposedly ignored him ("guys in rails issues ingored me and my issue"). So, kudos to Egor!
Thanks! In my case I did something similar to the following:
locals: { show_price: defined?(show_price) ? show_price : false }
In case anyone wants the coffeescript. Note that I kept the
.submit
bit in addition to.keyup
in case the user hits submit.I decided against the Endless Page feature, and instead slightly adapted this RailsCast's code to provide a "Show more results" link, which would append results in much the same manner, but instead by click rather than reached-bottom-of-page detection.
The main change is the addition of the prepend line in
products.js.coffee
:Regarding the view, I only added a surrounding div:
And in
products/index.js.erb
I just changed theremove
line to$('#append_and_paginate').remove();
so that both the "Show more results" link and pagination is removed when no more results are available.Of course some css had to be added to make things look nice.
But anyway, the cool thing about this approach is that the "Show more products" link is only added by Javascript (hence only if Javascript is present and enabled). The click handler is bound to the DOM element with id="append_more_results", which is the id of the link tag that is prepended.
I have a
respond_to
block in the index action of my controller, so I had to addformat.js
to render the RJS template associated with this action (i.e./app/views/products/index.js.erb
):Is the following change justifiable?
from:
to:
Ref: http://rhnh.net/2010/06/30/acts-as-list-will-break-in-production
@Alexander Zubkov, thanks a lot for posting your module! I tried it out and it works! My preference though, is not for
max+1
butmax of a particular set +1
. So I used your module as inspiration, but ended up doing this manually as follows.This works just as I want, but I wonder if there's a way to make this into a module! You'd have to be able to tell the callback method (set_position) which column (in this case "edition_id") to use in the
where
clause. I'm too new to RoR to be able to figure this out. Any suggestions?Let's say you wanted to add sort order to the results in my comment above, then you could do this:
And then you could refactor like this:
And if you also wanted to search
description
you might do this:Next, change your controller to pass the whole
params
rather than justparams[:search])
:Then update your
search
method accordingly:Why do all this? Because if you had more fields in your search view, you could easily search them too! For instance, let's say you change the above view to also include min price and max price:
Then in the search method, you do:
And for style you could change your view to use
search_field_tag
,size
, andplaceholder
:I hope this helps someone. For more info, see: http://railscasts.com/episodes/111-advanced-search-form-revised
Please copy/paste the controller's
index
action, and the model'ssearch
method.For Rails 3 compatibility, the ActiveRecord queries in the search method should look like this:
See http://railscasts.com/episodes/202-active-record-queries-in-rails-3 and http://m.onkey.org/active-record-query-interface
This is due to a Rails 3 change:
See "7.4.2 Helpers with Blocks" in http://edgeguides.rubyonrails.org/3_0_release_notes.html
Refer to "ranked model" in @Jean's comment above
If using Rails 3, see: http://rubygems.org/gems/acts_as_tree_rails3
In case anyone gets stumped by
task.save(false)
, as of rails 3 usetask.save(validate: false)
.See 3.0 release notes:
save(false) is deprecated, in favor of save(:validate => false)
and the API.The related error you may see is