【问题标题】:Getting countries states and cities in rails让国家和城市进入铁路
【发布时间】:2019-09-03 16:01:32
【问题描述】:

我有一个用于用户信息的嵌套模型的用户模型,并且我已经有一个带有country_select gem 的工作国家字段,但它不提供州和城市。

经过一番研究,我发现了这颗宝石ruby geocoder,正如它在文档中所说:

在任何基于机架的框架中 检测 HTTP 请求的位置 获取当前用户的城市和国家(使用 IP 地址)。一个 location 方法被添加到标准 Rack::Request 中,它返回一个 Geocoder::Result 对象:

# Rails controller or Sinatra app
city = request.location.city
country = request.location.country_code

基本上我想使用country_select gem 下车并使用ruby geocoder

我有两个模型:

models/user.rb

class User < ApplicationRecord
  extend FriendlyId
  friendly_id :username, use: :slugged
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

  has_one_attached :avatar, :dependent => :destroy
  # User Information
  has_one :user_information, :dependent => :destroy
  accepts_nested_attributes_for :user_information, :allow_destroy => true

  def with_user_information
    build_user_information if user_information.nil?
    self
  end

  # Login with username or email
  attr_accessor :login       
  validates :username, uniqueness: true, presence: true

  def login
    @login || self.username || self.email
  end

  def self.find_for_database_authentication(warden_conditions)
    conditions = warden_conditions.dup
    if login = conditions.delete(:login)
      where(conditions.to_h).where(["lower(username) = :value OR lower(email) = :value", { :value => login.downcase }]).first
    elsif conditions.has_key?(:username) || conditions.has_key?(:email)
      where(conditions.to_h).first
    end
  end
end

还有一个嵌套模型:

models/user_information.rb

class UserInformation < ApplicationRecord
  belongs_to :user

  has_one :gender, :dependent => :destroy
  accepts_nested_attributes_for :gender, :allow_destroy => true

  has_one :relationship, :dependent => :destroy
  accepts_nested_attributes_for :relationship, :allow_destroy => true

  def age
    now = Time.current
    dob = self.born_in
    now.year - dob.year - ((now.month > dob.month || (now.month == dob.month && now.day >= dob.day)) ? 0 : 1)
  end

  def country_name
    country = ISO3166::Country[country_code]
    country.translations[I18n.locale.to_s] || country.name
  end
end

这是我的设计控制器

controllers/accounts_controller.rb

class AccountsController < Devise::RegistrationsController

  def update
    self.resource = resource_class.to_adapter.get!(send(:"current_#{resource_name}").to_key)
    prev_unconfirmed_email = resource.unconfirmed_email if resource.respond_to?(:unconfirmed_email)
    resource_updated = update_resource(resource, account_update_params)
    yield resource if block_given?
    if resource_updated
      set_flash_message_for_update(resource, prev_unconfirmed_email)
      bypass_sign_in resource, scope: resource_name if sign_in_after_change_password?
      session[:return_to] ||= request.referer
      redirect_to session.delete(:return_to)
    else
      clean_up_passwords resource
      set_minimum_password_length
      session[:return_to] ||= request.referer
      redirect_to session.delete(:return_to), alert: resource.errors.full_messages[0]
    end
  end

  def settings
    @user = current_user
    if @user
      render "devise/accounts/settings"
    else
      render file: 'public/404', status: 404, formats: [:html]
    end
  end

  def passwords
    @user = current_user
    if @user
      render "devise/accounts/passwords"
    else
      render file: 'public/404', status: 404, formats: [:html]
    end
  end

  def security
    @user = current_user
    if @user
      render "devise/accounts/security"
    else
      render file: 'public/404', status: 404, formats: [:html]
    end
  end

  protected

  def update_resource(resource, params)
    if params[:current_password].blank? && params[:password].blank? && params[:password_confirmation].blank? && params[:email].blank?
     resource.update_without_password(params.except(:current_password, :password, :password_confirmation, :email))
    else
      resource.update_with_password(params)
    end
  end
end

【问题讨论】:

    标签: ruby-on-rails ruby rails-geocoder


    【解决方案1】:

    如果你想用geocoder 替换country_select,你只需要在你需要的控制器中取这个值。

    class UsersController < ApplicationController
      ...
      def create
       @user = User.new(user_params)
       @user.user_information.country = country_name(request.location.country_code)
       @user.user_information.city = request.location.city
       @user.save
      end
    end
    

    如果您使用的是设计...

    # app/controllers/registrations_controller.rb
    class RegistrationsController < Devise::RegistrationsController
      def new
        super
      end
    
      def create
        # put above logic here
      end
    
      def update
        super
      end
    end
    

    您需要实现所需的帮助程序/模型方法。

    【讨论】:

    • 这是否意味着我必须覆盖设计创建操作?
    • 我不知道您使用的是 Devise。在这种情况下,只需简单地将 UserController 更改为 RegistrationsController。更新了答案。
    • 我相信你的时间非常宝贵,我是 Rails 新手,我希望能带我一步一步来了解如何实现这一点。我已经有一个设计控制器,我会更新我的问题,然后记住我的 user_information.rb 是一个嵌套模型,属于设计 user.rb 。你对实现帮助器/模型方法是什么意思?
    • 嵌套模型在这里没什么大不了的,因为 Devise 可以处理它。使用助手/模型方法,我的意思是,如果您复制/粘贴我的解决方案,它仍然需要实现 country_name 方法,即它可能类似于 UserInformation.new.country_name(country_code) ,但这取决于您。
    • 为了让它工作,我需要设置geocoded_by :ip_address?文档没有提供如何真正设置它,我仍然不知道我应该做什么
    猜你喜欢
    • 2022-06-15
    • 1970-01-01
    • 1970-01-01
    • 2014-09-08
    • 2016-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多