I'm trying to pass a variable from my controller to a custom activeadmin page but I can't seem to figure it out.
I basically have a form that uploads a file and it parses it. If it reaches an error, it throws one and redirects to the custom page.
class ToolController < ApiController
def import
begin
Schedule.Parse(data)
rescue MissingDependencyError => e
#dependencies = "test"
redirect_to admin_import_path({}.merge(flash_error: "Missing Dependencies", dependency_error: true, :locals => { :m => e.object }))
end
end
class MissingDependencyError < StandardError
attr_reader :object
def initialize(object)
#object = object
end
end
ActiveAdmin.register_page "Import" do |lab|
menu false
content do
#dependencies
end
end
#dependencies comes back as nil -> why?
I can pass it through the params hash but that's not the right way.
Instance variables are not available after a redirect_to ... the redirect_to creates a new controller instance and all the instance variables of the previous controller object are gone.
Instead of the params hash, you can use the sessions hash
session[:dependencies] = "test"
and
content do
session[:dependencies]
end
Related
I have an extension for RefineryCMS. In that extension I need to get data from object Block in the PagesController.
My code:
def show
if should_skip_to_first_child?
redirect_to refinery.url_for(first_live_child.url) and return
elsif page.link_url.present?
redirect_to page.link_url and return
elsif should_redirect_to_friendly_url?
redirect_to refinery.url_for(page.url), :status => 301 and return
end
#block = Refinery::Blocks::BlocksController::Block.find_by(:name => 'Footer')
render_with_templates?
end
In development the first launch is successful, but after refreshing or redirecting to another site's page:
uninitialized constant Refinery::Blocks::BlocksController::Block
can you paste whole code of your controller and model.
I think problem in this line.
#block = Refinery::Blocks::BlocksController::Block.find_by(:name => 'Footer')
You are trying to access from controller.
Use Model name like
Module::Model.find_by(:name => "Footer")
Answer: https://github.com/refinery/refinerycms/issues/3051
I'm making a breadcrumb module for my Ruby on Rails application, but I wanted a specific syntax - which I thought was good looking and more intuitive for Rails developers.
Here's the deal:
class WelcomeController < ApplicationController
breadcrumb_for :index, :text => 'Home', :href => -> { root_path }
def index
end
end
See, it's neat.
You can safely ignore the everything else but that proc - what I assign to the :href key.
I use instance_eval so that when the proc is evaluated it has access to the root_path helper.
And it worked. The example above is okay. BUT then I wanted to use an instance variable and that didn't work.
Like this:
class WelcomeController < ApplicationController
breadcrumb_for :index, :text => 'Home', :href => -> { #path }
def index
#path = root_path
end
end
Now, in that proc context #path is nil.
What should I do so I can access the instance variables from the block ?
Below is all the code of my module. Note that when I "process" the blocks and use instance_eval (aka call my module's #breadcrumb) the action should already be evaluated so the instance variable #path should already exist.
module Breadcrumb
extend ActiveSupport::Concern
included do
cattr_accessor(:_breadcrumb) { [] }
helper_method :breadcrumb
def self.breadcrumb_for(*args)
options = args.pop
_breadcrumb.push([args, options])
end
end
def breadcrumb
#breadcrumb ||= self._breadcrumb.map do |item|
puts item
if item[0].include?(params[:action]) || item[0][0] == '*'
text, href = item[1].values_at(:text, :href)
if text.respond_to?(:call)
text = instance_eval(&text)
end
if href.respond_to?(:call)
href = instance_eval(&href)
end
[text, href]
end
end
end
end
Oh no. I'm ashamed to say but it was my mistake. The code above works just fine, I was using different variable names in my application, not shown in the excerpt I used in the question.
Thanks anyway, I'll left it here for reference.
I have a route that matches /edit_account => accounts#edit since the account id isn't provided it's supposed to use the current user id and the account#edit method is shared with /accounts/[:id]/edit.
class AccountController < ApplicationController
...
def edit
# This doesn't work:
params = retrieve_id_if_missing(params)
# This works:
# aHash = params
# params = retrieve_id_if_missing(aHash)
end
def retrieve_id_if_missing(params)
# raise params.inpect => returns nil at this point
if params[:id].nil? and !logged_in?
redirect_to root_path
else params[:id].nil?
params[:id] = current_user.id
end
params
end
end
The problem I am having is that params, when passed to the class method, retrieve_id_if_missing, is becoming nil. However, if I assign params to another variable. e.g., aHash, before passing it to retrieve_id_if_missing it will contain the expected data, {"action" => "edit", "controller" => "account"}.
I've tried to search for a reason but have come up short, can someone explain to me why this is happening?
Have you tried
class AccountController < ApplicationController
...
def edit
retrieve_id_if_missing
end
def retrieve_id_if_missing()
if params[:id].nil? and !logged_in?
redirect_to root_path
else params[:id].nil?
params[:id] = current_user.id
end
params
end
end
I am fairly sure params will be in scope in the method.
Anyhow, check out gem devise for this. it should have everything you want and more
With devise you can just use
before_filer :authenticate_user!
At the top of your controller
https://github.com/plataformatec/devise
The Ruby interpreter is treating params as a local variable and initializing it with nil when it sees the assignment. This happens before it executes the retrieve_id_if_missing.
This is why explicitly assigning a value to the local variable before calling the method avoids the error, because the initialization to nil by Ruby doesn't happen.
The following examples demonstrate this:
Example #1
def foo(bar)
puts "foo bar: #{bar.class}"
end
bar = foo(bar) # => nil
puts "bar: #{bar.class}"
# Outputs:
# foo bar: NilClass
# bar: bar: NilClass
Example #2
a = a # => nil
puts "a: #{a.class}"
# Outputs:
# a: NilClass
Example #3
a = 123 if a # => nil
puts "a: #{a.class}"
# Outputs:
# a: NilClass
References:
Why is a = a nil in Ruby?
Ruby interpreter initializes a local variable with nil when it sees an
assignment to it. It initializes the local variable before it executes
the assignment expression or even when the assignment is not reachable
(as in the example below). This means your code initializes a with nil
and then the expression a = nil will evaluate to the right hand value.
a = 1 if false a.nil? # => true The first assignment expression is not
executed, but a is initialized with nil.
Ruby: method inexplicably overwritten and set to nil
Here's another example:
a = 123 if a # => nil a # => nil We shouldn't be able to say if a
because we never set a, but Ruby sees the a = 123 and initializes a,
then gets to if a at which point a is nil
I'd consider it a quirk of the interpreter, really. Gary Bernhardt
makes fun of it in wat (https://www.destroyallsoftware.com/talks/wat)
with a = a
While I cannot answer why your params object would be overridden with the code provided, here are some thoughts.
class AccountController < ApplicationController
before_filter :retrieve_id_if_missing, only: :edit
def edit
# You'll find params[:id] prepopulated if it comes here,
# else the request has been redirect
end
protected
# There should be no need to pass the params object around, it should be accessible everywhere
def retrieve_id_if_missing
if logged_in?
params[:id] ||= current_user.id # conditional assignment will only happen if params[:id] is nil
end
# Redirect to root if params[:id] is still blank,
# i.e. user is not logged in and :id was not provided through route
if params[:id].blank?
flash[:alert] = 'You need to be logged in to access this resource.'
return redirect_to root_url # early return!
end
end
end
I have a model Token with three fields user_id,product_id and unique_token.In the controller i instantiate a #token object with user_id and product_id values collected from the form.Then i call save_with_payment function with that object,where within the function i want to generate random string 3 times and save in unique_token field.The problem is self.tokens.create!( unique_token: Digest::SHA1.hexdigest("random string") ) give me no method error undefined method tokens.What am i doing wrong here?To clarify what i want to accomplish,I want to be able to retrieve list of generated unique_tokens associated to that user_id or product_id like User.find(1).tokens or Product.find(1).tokens.The model association is User has_many Tokens Product has_many Tokens.Note: unique_token field is from Token model originally,user_id and product_id are just ref primary keys.Much Thanks!
def create
#token=Token.new(params[:token])
if #token.save_with_payment
redirect_to :controller => "products", :action => "index"
else
redirect_to :action => "new"
end
end
class Token < ActiveRecord::Base
require 'digest/sha1'
def save_with_payment
# if valid?
# customer = Stripe::Charge.create(amount:buck,:currency => "usd",card:stripe_card_token,:description => "Charge for bucks")
#self.stripe_customer_token = customer.id
3.times do
self.tokens.create!(unique_token: Digest::SHA1.hexdigest("random string"))
end
save!
end
end
There is no tokens method on the Token class. Since you're creating three tokens you don't need the #token instance. Just have save_with_payment be a class method:
def create
if Token.save_with_payment(params[:token])
redirect_to :controller => "products", :action => "index"
else
redirect_to :action => "new"
end
end
class Token < ActiveRecord::Base
require 'digest/sha1'
def self.save_with_payment(attributes)
attributes.merge!(unique_token: Digest::SHA1.hexdigest("foo"))
3.times do
self.create!(attributes)
end
end
end
Hope this helps.
You might want to wrap the loop in a begin/rescue, too. Otherwise if the 2nd or 3 create! fails you end up with tokens AND redirecting to "new".
Response to 1st comment:
That won't work if you use a class method. You can't call valid? because you're not in the context of an instance of Token. I don't recommend sticking with an instance method. If you do change it to a class method you'll want to wrap it in a transaction block:
def self.save_with_payment(attributes)
transaction do
attributes.merge!(unique_token: Digest::SHA1.hexdigest("foo"))
3.times do
self.create!(attributes)
end
rescue
false
end
end
That should roll back the SQL transactions if any of the create! calls fail and return false to the controller create action.
I'd pull that customer code out of Token (Token shouldn't care about creating/retrieving a customer) and put it in the controller action. Pass the pertinent information into save_with_payments. Like:
self.save_with_payments(customer, attributes)
...
end
I am building a small application in RoR that has a form asking for a URL. Once the URL has been filled in and submit button is pressed I have downloaded a web-scraping plugin scrAPI(which is working fine) which gets the of URL and creates a record in db with title.
My issue right now is that I am able to make the whole thing work if the URL is valid and scrAPI is able to process it. If a URL entered does not work it gives this "Scraper::Reader::HTTPInvalidURLError" which is expected, but my knowledge of working in Model is preventing me from handing that error in a correct manner.
Controller:
#controller
class ArticleController < ApplicationController
def savearticle
#newarticle = params[:newarticle]
#link = #newarticle["link"]
#id = #newarticle["id"]
Article.getlink(#link)
success = Article.find(:last).update_attributes( params[:newarticle] )
if success
render :partial => 'home/articlesuccess'
else
render :partial => 'home/articlebad'
end
end
end
# model
require 'scrapi'
class Article < ActiveRecord::Base
attr_accessor :getlink
def self.getlink(link)
scraper = Scraper.define do
process "title", :title => :text
result :title
end
uri = URI.parse(link)
Article.create(:title => scraper.scrape(uri))
end
end
How to:
1) Handle the Scraper::Reader::HTTPInvalidURLError properly, so text could be returned to view with proper error.
2) I would also like to know how I can return 'uri' from model and use it in the controller or view.
3) Also, I would like to return the ID of the Article created in Model so I can use that in the controller instead of doing find(:last) which seems like bad practice.
Something like...
class ApplicationController < ActionController::Base
rescue_from 'Scraper::Reader::HTTPInvalidURLError', :with => :invalid_scrape_url
private
def invalid_scrape_url
flash[:error] = 'The URL for scraping is invalid.'
render :template => 'pages/invalid_scrape_url'
end
end
rescue_from is what you need.
That's 1)
for 2) You could just use #uri but personally I'd create a new model called Scrape and then you can retrieve each Scrape that is attempted.
for 3) I'm not quite sure of the question but
#article = Article.create(:title => scraper.scrape(uri))
then
#article.id
Hope that helps!
(1) In Ruby, you can handle any exception as follows:
begin
# Code that may throw an exception
rescue Scraper::Reader::HTTPInvalidURLError
# Code to execute if Scraper::Reader::HTTPInvalidURLError is raised
rescue
# Code to execute if any other exception is raised
end
So you could check for this in your controller as follows:
begin
Article.getlink(#link)
# all your other code
rescue Scraper::Reader::HTTPInvalidURLError
render :text => "Invalid URI, says scrAPI"
rescue
render :text => "Something else horrible happened!"
end
You'll need to require 'scrapi' in your controller to have access Scraper::Reader::HTTPInvalidURLError constant.
I would probably make the creation of the new Article and the call to scrAPI's method separate:
title = scraper.scrape(uri)
Article.create(:title => title)
(2) and (3) In Ruby, the last statement of a method is always the return value of that method. So, in your self.getlink method, the return value is the newly created Article object. You could get the ID like this in your controller:
article = Article.getlink(#link)
article_id = article.id
You may need to refactor the code a bit to get the results you want (and make the code sample on the whole cleaner).