As preface, I've followed through some tutorials (i.e. Michael Hartl's) though I'm still fairly novice. Forgive any cloudy terminology.
I am trying to build a simple application in Rails 4 that does the following:
User logs into application (currently working with sign-in-with-twitter link and routing)
get "/auth/:provider/callback" => "sessions#create"
get "/signout" => "sessions#destroy", :as => :signout
Once <% if current_user %> is true, I have the view rendering a partial where there will be a list of simple buttons. When the user clicks a button I want the application to tweet on behalf of the current_user a preset string. Ideally, I'd do this all in ruby/rails.
These button functions are where I'm getting hung up. I've read a fistful of documents but there seem to be a lot of conflicting and old answers. Here's a quick list of the ones I think are closest, though not explicit about sending a tweet from a simple button/link in a view:
http://www.sitepoint.com/ruby-social-gems-twitter/
http://richonrails.com/articles/sending-a-tweet-to-twitter
Some call for controllers, a more robust oauth setup (which I have bundle installed and connected to the dev.twitter application, though not fleshed out beyond keys), and whatever else. It's got me turned around and I'm not yet good enough to synthesize all the information. Any help and direction would be great. Below are some other files in the app that might be helpful.
class SessionsController < ApplicationController
def create
auth = request.env["omniauth.auth"]
user = User.find_by_provider_and_uid(auth["provider"], auth["uid"]) || User.create_with_omniauth(auth)
session[:user_id] = user.id
redirect_to root_url, :notice => "Hi!"
end
def destroy
session[:user_id] = nil
redirect_to root_url, :notice => "Bye!"
end
end
And omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
provider :twitter, '_priv', '_priv'
end
Eep! I'm the author of the second link (RichOnRails). Did you take a look at the example app included with the tutorial? It does almost exactly what you want. If the tweets are hard coded you could approach it in a couple of different ways. If you take a look at the tweets controller, you'll see it takes a parameter called 'message'. Any message passed to that create method will tweet as the current user.
def create
current_user.tweet(twitter_params[:message])
end
The easiest (but not necessarily best) way to adapt this to fit your needs is to have a form for each tweet, and do a hidden field with the message you wish to tweet. The button becomes a submit for that particular form (you can add remote: true if you want to keep the page from refreshing, then use a bit of javascript to update the UI elements). Hope this helps.
Related
We are building a Rails4 app using Trailblazer. I have never worked with Trailblazer before and I am confused about how to do things.
We are building an auction site. I was previously using a traditional controller, and this route endpoint was working fine:
def bill
#profile = Profile.find_by user_id: current_user_id
#current_order = Order.order(created_at: :desc).find_by(user_id: current_user_id)
#batch = #current_order.batch
if #batch.nil?
puts "There was no batch linked to the current order of #{#current_order.id}"
flash[:error] = "We are sorry, but we could not determine which batch your order belongs to."
else
#price_shown_to_customer = #batch.price + ENV["FUELBID_FEE_PER_GALLON"].to_f
#amount = #current_order.quantity * #price_shown_to_customer
end
But now I'm suppose to create this as a Trailblazer api, using a Representer class.
So in routes.rb I added something for "charges":
namespace :api do
get '/price' => 'info#info'
post '/order' => 'orders#create'
get '/charges' => 'charges#bill'
end
I created this Api but copying-and-pasting another:
module Api
class ChargesController < ApiApplicationController
respond_to :json
def bill
respond_with OpenStruct.new.extend(ChargesRepresenter)
end
end
end
I tested the above with a simple Representer and it all worked fine, so everything is good up to this point. If I return simple data from the Representer, then I can see it fine here:
http://localhost:3000/api/charges.json
But I need to get the current_user. How is this done? Right now, this does not work:
module ChargesRepresenter
include Roar::JSON
collection :price_shown_to_customer
def price_shown_to_customer
current_order = Order.order(created_at: :desc).find_by(user_id: current_user_id)
puts "current_order"
puts current_order.id
batch = current_order.batch
batch.price + ENV["FUELBID_FEE_PER_GALLON"].to_f
end
end
current_user_id exists in my traditional controllers because we set up Devise and so my traditional controllers inherit it:
class ChargesController < SecuredController
But is there any way to get it in a Trailblazer Representer?
Hope this answer is not too late.
If you can switch to Decorator pattern instead of a Module.
Representer really doesn't need to know and doesn't care if it is called from controller or console or test. All it needs is a hash to build your json object from. So you can just pass another attribute called current_user_id to your Representer and then use it inside r presenter like you do.
FYI:
If you need a more immediate response you can also copy your question to https://gitter.im/trailblazer/chat . There are usually several people hanging out there. But it's also good to post a question here for posterity.
Two controllers: Users and Tasks.
Main page for Users = Users/user_id.
Form on main page used to input data into tasks model.
This process handled by the Tasks Controller.
Successful input: redirect and load tasks from database, OK, all working.
Unsuccessful input, just need to refresh main page so we keep form input and specialised (non-flash) error messages
I can't seem to get the Tasks Controller to deliver the original page. Error is Missing template users/1(which is the correct syntax if I were to visit in my browser).
Should I be calling an action and passing params? Any help for this beginner would be really appreciated.
def create
#task = current_user.tasks.build(task_params)
if #task.save
flash[:success] = "New task created!"
redirect_to user_url(current_user)
else
flash[:error] = "Task not saved! Please see guidance by form labels"
render "users/#{current_user.id}"
end
end
private
def task_params
params.require(:task).permit(:label, :address, :content)
end
end
users/1 is not a template, it's a path. users/show is the template in this case.
mind that the only reason to use render is to render a template in the scope of your current controller action rather than the normal one.
i.e. you probably need to have #user etc set, or the users/show template will be upset about missing variables.
In this case it might be easier just to redirect_to user_path(id) and allow the users/#show controller action set up the #user variable etc.
I've been running into quite an annoying issue when dealing with Rails 4 action mailer previews and factory girl. Here's an example of some of my code:
class TransactionMailerPreview < ActionMailer::Preview
def purchase_receipt
account = FactoryGirl.build_stubbed(:account)
user = account.owner
transaction = FactoryGirl.build_stubbed(:transaction, account: account, user: user)
TransactionMailer.purchase_receipt(transaction)
end
end
This could really be any action mailer preview. Lets say I get something wrong (happens every time), and there's an error. I fix the error and refresh the page. Every time this happens I get a:
"ArgumentError in Rails::MailersController#preview
A copy of User has been removed from the module tree but is still active!"
Then my only way out is to restart my server.
Am I missing something here? Any clue as to what is causing this and how it could be avoided? I've restarted my server 100 times over the past week because of this.
EDIT: It may actually be happening any time I edit my code and refresh the preview?
This answers my question:
https://stackoverflow.com/a/29710188/2202674
I used approach #3: Just put a :: in front of the offending module.
Though this is not exactly an answer (but perhaps a clue), I've had this problem too.
Do your factories cause any records to actually be persisted?
I ended up using Factory.build where I could, and stubbing out everything else with private methods and OpenStructs to be sure all objects were being created fresh on every reload, and nothing was persisting to be reloaded.
I'm wondering if what FactoryGirl.build_stubbed uses to trick the system into thinking the objects are persisted are causing the system to try and reload them (after they are gone).
Here's a snippet of what is working for me:
class SiteMailerPreview < ActionMailer::Preview
def add_comment_to_page
page = FactoryGirl.build :page, id: 30, site: cool_site
user = FactoryGirl.build :user
comment = FactoryGirl.build :comment, commentable: page, user: user
SiteMailer.comment_added(comment)
end
private
# this works across reloads where `Factory.build :site` would throw the error:
# A copy of Site has been removed from the module tree but is still active!
def cool_site
site = FactoryGirl.build :site, name: 'Super cool site'
def site.users
user = OpenStruct.new(email: 'recipient#example.com')
def user.settings(sym)
OpenStruct.new(comments: true)
end
[user]
end
site
end
end
Though I am not totally satisfied with this approach, I don't get those errors anymore.
I would be interested to hear if anyone else has a better solution.
So I am trying to override Devise::RegistrationsController which they do have wiki for and tons of tutorial out there. The one thing that I can not find is the best implementation of how to override the controller whilst implementing the require admin approval feature as well.
I think I got the hang of it but before I go any further (from all the reading on the Devise's source code) I want to know, on the registrations controller there's a line that does:
resource.active_for_authentication?
However, on the Sessions controller it's just this:
def create
self.resource = warden.authenticate!(auth_options)
set_flash_message(:notice, :signed_in) if is_flashing_format?
sign_in(resource_name, resource)
yield resource if block_given?
respond_with resource, location: after_sign_in_path_for(resource)
end
What I want to know is, if it's not confirmed or the active_for_authentication returns false, where or how does the session controller check this? I tried tracing back the source code but no luck.
So anyone who's very familiar with Devise perhaps you could answer my question? Thank you.
After authenticating a user and in each request, Devise checks if your model is active by calling model.active_for_authentication?. This method is overwritten by other devise modules. For instance, :confirmable overwrites .active_for_authentication? to only return true if your model was confirmed.
You can overwrite this method yourself, but if you do, don't forget to call super:
def active_for_authentication?
super && special_condition_is_valid?
end
Whenever active_for_authentication? returns false, Devise asks the reason why your model is inactive using the inactive_message method. You can overwrite it as well:
def inactive_message
special_condition_is_valid? ? super : :special_condition_is_not_valid
end
I am currently having a bit of a problem with Globalize gem.
I explain the current situation:
I have a Model called Question. After creating it, without any data stored, I added the following lines to the model:
class Question < ActiveRecord::Base
translates :wording, :answer1, :answer2, :answer3, :answer4
end
Then, I created a migration to create the translations table
class CreateTranslationsTable < ActiveRecord::Migration
def up
Question.create_translation_table! :wording => :string, :answer1 => :string, :answer2 => :string, :answer3 => :string, :answer4 => :string
def end
def down
Question.drop_translation_table!
def end
My default locale is :en. After that I added some data.
If I go execute rails c and put the command Question.first.wording everything works fine.
Although when I execute in 'rails c' I18n.locale = :es and then I do Question.first.wording still displays the english text I put at the beginning.
I tried one thing which it seemed to help me is that I dropped all the translated columns (like specified in Globalize documentation after you migrated data. In my case I didn't have any data to migrate at the beginning though). After that I made a rollback (which got back the columns I deleted form the Question model), then executing Question.first.wording with I18n.locale = :es got it working. Which means that Question.first.wording returns nil.
After that, I implemented the 'Locale from Url Params' as specified in the Ruby on Rails guide
Which means the first URL param si the ':locale' param.
Now the current problem: The view still displays the information in English when it should display it in Spanish, since the URL I entered was http://localhost.com/es/questions/.
How can I make it to display in the view the Spanish information?
My mistake. I interpreted from the documentation that the the chunck of code (in application_controller.rb) that works for setting the url:
def default_url_options(options={})
{ locale: params[:locale] }
end
would actually set the 'I18n.locale' variable. What I did is the next to get around this (in application_controller.rb):
before_action :change_to_current_locale
def change_to_current_locale
I18n.locale = params[:locale]
end
That made it work.