There's got to be an easy way to do this, but I cannot find an answer...
When some creates or updates a WorkRequest in my app, I do other processing, including creating a Workflow object. I do some checking to make sure, for example, there isn't more than one Workflow already created for this WorkRequest. If there is, I want the update/create to fail with an error message. I just can't see how to do this. I tried returing false from my before_update callback method, but this did not work.
Do I raise an error and rescue it in my controller? What is the right way to do this in Rails 3?
Any help would be much appreciated.
This is why you have validations. You can implement an own validation like this:
class ...
validate :my_validation
def my_validation
if workflows > 1
errors.add(:workflow, "cannot be more than one" )
end
end
end
Related
I am trying to use a different warden strategy to authenticate my action cable end points.
But the strategy is not getting called. I tried to place warden.authenticate!(:action_cable_auth) in a controller to test but none of the debug statements are getting printed on console.
Below are the relevant part of the code.
config/initializers/warden.rb
Warden::Strategies.add(:action_cable_auth) do
def valid?
#check if its a websocket request & for action cable?
#Rails.logger.error request.inspect
p 'checking if strategy is valid?'
true
end
def authenticate!
p 'unauthenticate the user'
fail!('user not active')
end
end
in my controller
warden.authenticate!(:action_cable_auth)
Assuming that you are setting your initializer in the proper place, please recall that if your session is already instantiated somewhere else (for example if you authenticate the user at the point your action is being called, then your strategy will never be called.
This is basically how warden works: if some valid? strategy returns a success! then no other will be called as soon as any authenticate! method in the list of strategies is successful.
Please also be sure that if you want your strategy up the list of strategies to check you may need to also shift it up on the list, such as:
manager.default_strategies(scope: :user).unshift(:action_cable_auth)
Where the manager is your Warden::Manager instance. The scope may also be optional (this is an example where the user scope is used alongside Devise), but you may check your instance .default_strategies to figure out where it is and where you want it.
I have set up a very simple rails 5 project to narrow down my problem:
https://github.com/benedikt-voigt/capybara_js_demo
In this project the data mutation done by the Capybara JS is not deleted, neither by Rails nor by the Database cleaner I added.
The following great blog argues, that no DatabaseCleaner is needed:
http://brandonhilkert.com/blog/7-reasons-why-im-sticking-with-minitest-and-fixtures-in-rails
but this works only for fixtures, not for the mutation done by an out-of-thread Capybara test.
I added the Database cleaner, but this also needed work.
Does anybody has a sample setup?
From a quick look at your test I would say it's leaving data because the data is actually being added after DatabaseCleaner cleans. The click_on call occurs asynchronously, so when your assert_no_content call happens there's no guarantee the app has handled the request yet or the page has changed yet and since the current page doesn't have the text 'Name has already been taken' on it the assertion passes and the database gets cleaned. While that is happening the click gets processed by the app and the new data is created after the cleaning has occurred. You need to check/wait for content that will appear on the page after the click - something like
page.assert_text('New Foo Created')
You should only be asserting there is no content once you already know the page has changed, or you're expecting something to disappear from the current page.
I solved now the problem by setting the DB connection to one
class ActiveRecord::Base
mattr_accessor :shared_connection
##shared_connection = nil
def self.connection
##shared_connection || ConnectionPool::Wrapper.new(:size => 1) { retrieve_connection }
end
end
ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
as describe here:
https://mattbrictson.com/minitest-and-rails
I uploaded the working repo here:
https://github.com/benedikt-voigt/capybara_js_demo_working
In my "create" action on a form, I successfully save (1) MyObject to my local database and (2) OtherObject to a third-party database via its Ruby API. When something goes wrong with the save to the third party, I get an error in the form of a Ruby exception.
My question is: How do I stop the form submit and report the exception message to the client?
If this is not possible, what would be the best alternative?
Depending on whether you want to rollback your local database call, you might want to consider using Transactions. Something along these lines:
def create
ActiveRecord::Base.transaction do
#myobject = MyObject.create!(params[:myobject])
begin
# call third-party
rescue Exception => e
flash[:exception] = e.message
raise ActiveRecord::Rollback # Raise this to cause a rollback on MyObject
end
end
# redirect_to or render... might have to pick depending on if you got an exception
end
This will store the exception message into the flash which you can use to display to the user. Note Do not store the entire Exception object into the flash, you will definitely see overflow errors if your exception objects are too big.
If you're not too concerned about rolling back the MyObject creation, then you can just use a simple begin...rescue similar to what I showed in my example. You may need to determine whether you want to do a redirect_to or render depending on whether an exception occurred, but you can always conditionally determine that based on whether flash[:exception].nil? is true or not.
I trying to load feeds from my blog but this is resulting in the error in the title mentioned.
The error message:
NoMethodError (undefined method `entries' for 0:Fixnum):
app/controllers/pages_controller.rb:6:in `home'
This is how I'm doing:
I created a file in the libfolder called blog_feeds.rb, that contains only the following:
module BlogFeeds
require 'feedzirra'
def load_feeds
feeds = Feedzirra::Feed.fetch_and_parse('http://blog.shigotodoko.com/feed')
end
end
And the line #6 for the error is:
#feeds = load_feeds.entries
Note that this error only occurs sometimes, not always.
So, any idea about what's going wrong here?
Thank you!
When fetching a feed, Feedzirra will return the HTTP status code instead of an object containing the feed entries, if the HTTP fetch results in an error (i.e. not a 200 or 3XX).
In order to handle this condition gracefully, check the type of the object you get back from fetch_and_parse by wrapping it in something like:
unless feeds.is_a?(Fixnum)
# work with the feeds object
else
# handle the error condition, retry, etc.
end
You should also be able to see these failures by fetching the feed in a browser repeatedly, if it's frequent enough.
Well, seems that was something wrong with my code before.
I was trying to randomize some posts and using something like this on the view:
#feeds.shuffle!.first(5)
In order to get the first 5 random posts.
And to fix it, I just replaced the shuffle! method for the shufflemethod.
Now, everything is working fine!
I am using Rails 3 and AJAX and have a parent object which is being created through and AJAX request. This parent is sent with children and saves them all. However, if a child has an error, Rails will stop the request. Is there any way to tell Rails to ignore this? I understand the proper thing to do is find the problem within the Javascript sending the request and fix it. However, for the sake of learning, is there a way to tell Rails that some errors might be ignorable?
To save without validating use:
#parent.save(:validate => false)
Also, don't forget you can create conditional validation rules if needs be. For example, add a virtual attribute (an instance variable that is not persisted to the DB) accessible via bare_bones?. Then modify a validator like so:
validates_presence_of :nickname, :unless => "bare_bones?"
Then, in your controller you would do something like this:
#parent = Parent.new params[:parent]
#parent.bare_bones = true
#parent.save()
Hope this helps.
You are looking for exception handling.
begin
#code that may contain errors
rescue
#what to do if an error is encountered
end