Active Admin create additional URL on unique field - activeadmin

I have an object Foo which has fields id and token (both are unique, both have db indexes). I want to be able to get to Foo 1 by going to url "/admin/foos/token-of-foo-1" in addition to being able to use the url "/admin/foos/1". I know that I will need to do something like the below in my routes.rb, but I'm having trouble. Help?
ActiveAdmin.routes(self) # keep this
get 'admin/???', to: 'admin/???' # add ...something

Hmm, some thoughts:
#admin/foo.rb
controller do
def find_resource
if params[:id].length == 16 # it's a token
end_of_association_chain.find_by_token(params[:id])
else
end_of_association_chain.find(params[:id])
end
end
end

For this kind of purposes I use this gem called FriendlyID. You can select which fields should form the URL slug, in your case the field token:
class Foo < ApplicationRecord
extend FriendlyId
friendly_id :token, use: :slugged
end
Let me know if you have more doubts on how to configure. It has a great integration with Active Admin.

Related

Set Multi Tenant in Active Admin Controllers (required for Searchkick index)

I am using Active Admin in my multi tenant app. I also use Searchkick which has a custom tenant specific index in each model:
class Budget < ApplicationRecord
multi_tenant :company
searchkick inheritance: true,index_name: -> { [MultiTenant.current_tenant.tenant_name, model_name.plural, Rails.env].join('_') }
end
The issue is that in AA this logic fails because on the tenant is set. I want to be able to set this in AA when updating a record.
For example I would update http://localhost:4000/admin/budgets/dt2kqvgm where dt2kqvgm is the Friendly ID of the record. So I want to call something like:
MultiTenant.current_tenant = Budget.friendly.find(params['budget']['company_id'])
when I create / update a record etc.
Currently I get:
undefined method `tenant_name' for nil:NilClass
because in my application controller the tenant is set based on the user authentication to scope the current company etc. In AA I want/ need to set this based on the params which it seems you can't access from the AA controller logic. My params look like this in AA:
{"utf8"=>"✓", "_method"=>"patch", "authenticity_token"=>"PrhNGnPvV1Qfb5RCwTVv4Wwz9tjf9SFy2VWDcyJXoFLytM8y5ZAyF7h8I7xa+fy01E9Fc/v2CvR52I4/LKOLHQ==", "budget"=>{"company_id"=>"9", "name"=>"qweqwe", "description"=>"qweqwe", "notes"=>"qwee", "flag_active"=>"1", "slug"=>"dt2kqvgm", "title"=>"qweqwe"}, "commit"=>"Update Budget", "controller"=>"admin/budgets", "action"=>"update", "id"=>"dt2kqvgm"}
I don't know if this is the best way to do this but it works. I am know it needs tweaks but it's a start - you needs to:
set an around_action filter
add permitted_params
around_action :set_tenant, only: :update
controller do
def set_tenant
MultiTenant.with(Company.find(resource.company_id)) do
yield
end
end
def permitted_params
params.permit location: %[ company_id ]
end
end
It would seem this is required for each controller. Perhaps there is a way to add this as a default AA filter?
I also added the filter to just the update action.

Insert values into API request dynamically?

I have an API request I'm writing to query OpenWeatherMap's API to get weather data. I am using a city_id number to submit a request for a unique place in the world. A successful API query looks like this:
r = requests.get('http://api.openweathermap.org/data/2.5/group?APPID=333de4e909a5ffe9bfa46f0f89cad105&id=4456703&units=imperial')
The key part of this is 4456703, which is a unique city_ID
I want the user to choose a few cities, which then I'll look through a JSON file for the city_ID, then supply the city_ID to the API request.
I can add multiple city_ID's by hard coding. I can also add city_IDs as variables. But what I can't figure out is if users choose a random number of cities (could be up to 20), how can I insert this into the API request. I've tried adding lists and tuples via several iterations of something like...
#assume the user already chose 3 cities, city_ids are below
city_ids = [763942, 539671, 334596]
r = requests.get(f'http://api.openweathermap.org/data/2.5/groupAPPID=333de4e909a5ffe9bfa46f0f89cad105&id={city_ids}&units=imperial')
Maybe a list is not the right data type to use?
Successful code would look something like...
r = requests.get(f'http://api.openweathermap.org/data/2.5/group?APPID=333de4e909a5ffe9bfa46f0f89cad105&id={city_id1},{city_id2},{city_id3}&units=imperial')
Except, as I stated previously, the user could choose 3 cities or 10 so that part would have to be updated dynamically.
you can use some string methods and list comprehensions to append all the variables of a list to single string and format that to the API string as following:
city_ids_list = [763942, 539671, 334596]
city_ids_string = ','.join([str(city) for city in city_ids_list]) # Would output "763942,539671,334596"
r = requests.get('http://api.openweathermap.org/data/2.5/group?APPID=333de4e909a5ffe9bfa46f0f89cad105&id={city_ids}&units=imperial'.format(city_ids=city_ids_string))
hope it helps,
good luck

Trying to point a puppet variable with the content of others variables

I'm writing a puppet code and need to point to a variable with the information of others.... to make it clear here is the example:
These are the variables with the information:
Array $users_ap1_dev = ['userdev1,userdev2'],
Array $users_ap2_prd = ['userprd1,userprd2'],
but ap1 and ap2 values are store in a fact calles main_app and dev and prd values are store in a fact called env.
I want to retrieve the info and create the user based on the fact information, something like
$dmz_users.each | String $user |{
user { $user:
ensure => 'present',
}
So, how can i put the content of $users_ap1_dev into dmz_users, replacing ap1 and dev with the one store in the fact?
something like?:
Array $dmz_user = "${users_${main_app}_${env}}"
Thanks a lot in advance for the help!
I found the answer, the function: getvar()
It allows you to create a variable and put his content into another...
How to use it:
$dmz_users = getvar("users_${main_app}_${env}")
So let's says $main_app = web and '$env = prod', it will take this two values and will make '$dmz_users = $users_web_prod`

ActionDispatch::ClosedError when testing Rails 3.1 model creation (RSpec/Cucumber)

I am creating a web application with Ruby on Rails 3.1 (RC1). I am using Factory Girl, RSpec and Cucumber (with Capybara) for testing, but I am experiencing unexpected raised ActionDispatch::ClosedErrors some of the times (not every time) when I am creating new users (through the User model's create action). Below is the error message that I get:
Cannot modify cookies because it was closed. This means it was already streamed
back to the client or converted to HTTP headers. (ActionDispatch::ClosedError)
The error is raised when using these ways of creating users:
Creation using Factory Girl
Factory.create( :user )
Factory.build( :user ).save
Basic creation
User.create( { ... } )
User.new( { ... } ).save
What is funny is that they do work during some test, but not in others, and it does not seem random, although I cannot figure out the reason. Below is an excerpt from my code:
users_controller_spec.rb
require 'spec_helper'
def user
#user ||= Factory.create( :user )
end
def valid_attributes
Factory.attributes_for :user
end
describe UsersController do
describe 'GET index' do
it 'assigns all users as #users' do
users = [ user ] # The call to user() raises the error here
get :index
assigns[ :users ].should == users
end
end
describe 'GET show' do
it 'assigns the requested user as #user' do
get :show, id: user.id # The call to user() raises the error here
assigns[ :user ].should == user
end
end
However, the error is not raised in the following code block:
describe 'GET edit' do
it 'assigns the requested user as #user' do
get :edit, id: user.id # This raises no error
assigns[ :user ].should == user
end
end
Any other method below this does not raise the error, even though I am creating users in the exact same way.
Any suggestions to what I might be doing wrong would be greatly appreciated!
Someone posted a workaround here
https://github.com/binarylogic/authlogic/issues/262#issuecomment-1804988
This is due to the way rails 3 streams the response now. They posted a fix in edge for the same issue in flash but not in cookies yet. For now I have turned off my request specs. I am going to look at the problem this weekend if no one gets to it before then.
https://github.com/rails/rails/issues/1452
Just so we don't have to follow links, here's my modified version of the authlogic workaround:
class User < ActiveRecord::Base
acts_as_authentic do |c|
c.maintain_sessions = false if Rails.env == "test"
end
end
Rather than deal with ensuring session management on every .save call, I just turn them off if I'm testing.

UserControl that embeds another user control, how to access embedded form fields?

I have a long form that the user has to fill out.
So I broke the form into logical units and created another user control for some elements (they will be reused elsewhere).
So say the form has these fields:
UserControl3.ascx
Username
password
email -- usercontrol2.ascx
address -- usercontrol2.ascx
city -- usercontrol2.ascx
state -- usercontrol2.ascx
So now in the codebehidn of usercontrol3.ascx, how will I access the usercontrol2.ascx's fields so I can write to the db?
Something like this works, but it is just not elegant:
Dim txtBox as TextBox = Ctype(parentControl.Controls(Index), System.Web.UI.Controls.TextBox)
stringVariable = txtBox.Text
The correct way to do it is to implement properties for your parentControl that access child's controls properties.
Public Property AddressField() as string
Set(byval value as string)
txtAddressField.Text = value
End Set
Get
Return txtAddressField.Text
End Get
End Property
if user control 3 contains user control 2, I would modify the code for user control 2 to expose public properties for the information that you need to retreive.
edit
There are other ways of doing it, but the property route is the safest route, and avoids strong dependencies between the two controls.

Resources