I wrote a test for controll with rspec:
it "populates an array of books" do
book = FactoryGirl.create(:book)
get :index
expect(:books).to eql([book])
end
books_controller.rb
def index
#books = Book.all.order("created_at DESC")
end
books.rb
FactoryGirl.define do
factory :book do |f|
f.name { Faker::Book.title }
f.author { Faker::Book.author }
f.press { Faker::Book.publisher }
f.cover { fixture_file_upload(Rails.root.join('spec', 'photos', 'testcover.jpg'), 'image/png') }
end
end
Run bin/rake spec, the result is:
1) BooksController GET #index populates an array of books
Failure/Error: expect(:books).to eql([book])
expected: [#<Book id: 1, name: "The Waste Land", author: "谢靖琪", isbn: nil, press: "University of Chicago Press"...e: "image/png", cover_file_size: 104531, cover_updated_at: "2016-08-26 04:00:19", page_number: nil>]
got: :books
(compared using eql?)
Diff:
## -1,2 +1,2 ##
-[#<Book id: 1, name: "The Waste Land", author: "谢靖琪", isbn: nil, press: "University of Chicago Press", description: nil, grade_level: nil, lexile_level: nil, douban_link: nil, scholastic_link: nil, created_at: "2016-08-26 04:00:19", updated_at: "2016-08-26 04:00:19", cover_file_name: "fcbcb7417dbc88827d16765a.jpg", cover_content_type: "image/png", cover_file_size: 104531, cover_updated_at: "2016-08-26 04:00:19", page_number: nil>]
+:books
They are not equal. It seems that the first expected result, '...' is an abbreviation. How can I fix it?
I think what you want is
expect(assigns(:books)).to eq([book])
Related
Given something like this:
hey = {
some_key: {
type: :object,
properties: {
id: { type: :string, example: '123', description: 'Id' },
created_at: { type: :string, example: '2019-02-14 14:13:55'},
updated_at: { type: :string, example: '2019-02-14 14:13:55'},
type: { type: :string, example: 'something', description: 'Resource type' },
token: { type: :string, example: 'token', description: 'Some description of token' }
}
}
}
I would like to go through all keys until I find one named properties, then mutate its content such that the keys become the value of a description key if it doesn't exit in its nested hash.
So for the example above, the hash would end up like this:
hey = {
some_key: {
type: :object,
properties: {
id: { type: :string, example: '123', description: 'Id' },
created_at: { type: :string, example: '2019-02-14 14:13:55', description: 'Created At'},
updated_at: { type: :string, example: '2019-02-14 14:13:55', description: 'Updated At'},
type: { type: :string, example: 'something', description: 'Resource type' },
token: { type: :string, example: 'token', description: 'Some description of token' }
}
}
}
created_at and updated_at didn't have a description.
It should also handle if token, for instance, had a properties property.
I came up with a solution that works but I am really curious on how I can improve it?
My solution below:
def add_descriptions(hash)
return unless hash.is_a?(Hash)
hash.each_pair do |key, value|
if key == :properties
value.each do |attr, props|
if props[:description].nil?
props.merge!(description: attr.to_s)
end
end
end
add_descriptions(value)
end
end
As I understand all you know about the hash hey is that it is comprised of nested hashes.
def recurse(h)
if h.key?(:properties)
h[:properties].each do |k,g|
g[:description] = k.to_s.split('_').map(&:capitalize).join(' ') unless
g.key?(:description)
end
else
h.find { |k,obj| recurse(obj) if obj.is_a?(Hash) }
end
end
recurse hey
#=> {:id=>{:type=>:string, :example=>"123", :description=>"Id"},
# :created_at=>{:type=>:string, :example=>"2019-02-14 14:13:55",
# :description=>"Created At"},
# :updated_at=>{:type=>:string, :example=>"2019-02-14 14:13:55",
# :description=>"Updated At"},
# :type=>{:type=>:string, :example=>"something",
# :description=>"Resource type"},
# :token=>{:type=>:string, :example=>"token",
# :description=>"Some description of token"}}
The return value is the updated value of hey.
First time I ask a question on this site, hope you can help me for my 'problem'. :-)
Actually, it's not really a problem in development, but in production...
Here's my problem:
I'm working with Rails 3.2.11 and ruby 2.1.7. For this, I'm using RubyMine.
Since the beginning, when I push some data in a hash, the record appears also in an user instance of collection.
I searched in my configuration, in my development.rb, initializers,... But I don't know where it comes! :-(
Because I don't have any reputation on this site, I can't show you what it is, so I will explain it in other way.
I add my User 'Test1' to a tournament via the view by clicking on 'sign in'.
My view (I'm using Haml):
app/views/tournaments/show.html.haml
%p#notice= notice
%p
%b Name:
= #tournament.name
%p
%b Place:
= #tournament.place
= #tournament.to_coordinates
%p
= image_tag "http://maps.google.com/maps/api/staticmap?size=450x300&sensor=false&zoom=16&markers=#{#tournament.latitude}%2C#{#tournament.longitude}"
%p
%b Nb players max:
= #tournament.nb_players_max
- if can? :update, #tournament
= link_to 'Add Match', new_match_path(#tournament.id)
|
= link_to 'Add Games', show_games_path(#tournament.id)
|
= link_to 'Edit', edit_tournament_path(#tournament)
|
= link_to 'Back', tournaments_path
- if #tournament.users.include?(#current_user)
%p
you\'re already signed in for this tournament
- else
= form_for #tournament, url: add_player_path, method: :post do |f|
= f.hidden_field 'tournament_id', :value => #tournament.id
= f.submit 'Sign in'
= link_to 'Seed players', seed_players_path(#tournament.id), method: :post
- if #tournament.users.any?
%ul.list-group
= #tournament.users.each do |player|
%li.list-group-item
= player.pseudo
- else
%p
No players for this tournament.
- if #tournament.games.any?
= #tournament.games.each do |game|
%h2
= game.title
= link_to 'Sign in all players'
- else
%p
No games for this tournament. A new game will be added rapidly.
by clicking on the sign in button, the user is correctly added in #tournament.users. But this appears also in the view just below :
- if #tournament.users.any?
%ul.list-group
= #tournament.users.each do |player|
%li.list-group-item
= player.pseudo
- else
%p
No players for this tournament.
[#<User id: 29, country: "BE", nb_victory: nil, nb_defeat: nil, total_points: nil, created_at: "2016-02-16 14:20:36", updated_at: "2016-02-18 10:07:49", first_name: "T", last_name: "T", pseudo: "Test1", email: "test1#test.com", encrypted_password: "$2a$10$WRHkX0mN0t1GAEYg8CQPJeVHBg0bVzBmDxpHKtU.g23A...", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 3, current_sign_in_at: "2016-02-18 10:07:49", last_sign_in_at: "2016-02-17 09:31:06", current_sign_in_ip: "127.0.0.1", last_sign_in_ip: "127.0.0.1", confirmation_token: "Q2rJ8aWYPmttd9XRjKgX", confirmed_at: nil, confirmation_sent_at: "2016-02-16 14:20:36", unconfirmed_email: nil, avatar: "chat.png", provider: nil, uid: nil, role: "player">]
In the HTML code, I can see this:
<ul class="list-group">
<li class="list-group-item"> Test1 </li>
[#<User id: 29, country: "BE", nb_victory: nil, nb_defeat: nil, total_points: nil, created_at: "2016-02-16 14:20:36", updated_at: "2016-02-18 10:07:49", first_name: "T", last_name: "T", pseudo: "Test1", email: "test1#test.com", encrypted_password: "$2a$10$WRHkX0mN0t1GAEYg8CQPJeVHBg0bVzBmDxpHKtU.g23A...", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 3, current_sign_in_at: "2016-02-18 10:07:49", last_sign_in_at: "2016-02-17 09:31:06", current_sign_in_ip: "127.0.0.1", last_sign_in_ip: "127.0.0.1", confirmation_token: "Q2rJ8aWYPmttd9XRjKgX", confirmed_at: nil, confirmation_sent_at: "2016-02-16 14:20:36", unconfirmed_email: nil, avatar: "chat.png", provider: nil, uid: nil, role: "player">]
</ul>
What's wrong with it? It seems a configuration problem.
First: please give a clear problem statement, so that we don't have to guess.
Your problem seem to be that data is written to you html that you don't want. It looks like a ruby-array : [#<User id: 29, country: "BE"....
Is this what is wrong?
Replace the = with a - before #tournament.users.each .
reason: The each call iterates over the array, but also returns the whole array after finishing. If you use a '=', this return value will be written into your html.
MurifoX was right!
Did you change = #tournament.users.each to - #tournaments.users.each?
Of course, if you use '=' in HAML, it's translated like '<%='. But, if we use '-' instead of '=', it's translated like '<%'.
the reason (from Meier):
reason: The each call iterates over the array, but also returns the whole array after finishing. If you use a '=', this return value will be written into your html.
That's it! Thank you everyone :-)
ps: When I can do it, I will up your answers :)
EDIT:
Dave Newton was right too ^^
Really hope this is actually possible but I can't seem to access my forms parameters to send with my custom action
My aim here is for a user to fill in their form, click on a Preview button that will show them what their post will look like, i have created the view which is fine, just passing the parameters is an issue.
This is my current form
# Create Blog Post
form do |f|
inputs 'Blog' do
f.semantic_errors
f.input :title
f.input :category_id, as: :select, collection: Category.all
f.input :comments, as: :text, input_html: { rows: 10, cols: 10 }
f.input :published, as: :boolean
end
inputs 'Submit' do
f.actions do
f.action :submit
f.action :cancel
f.action :reset
li do
link_to 'Preview', preview_my_admin_panel_posts_path(post: { title: "test", comments: 'comments', category_id: '1' }) # Hardcoded for now
end
end
end
end
# Collection Action to handle object
collection_action :preview, method: :get do
#post = Post.new(permitted_params[:post])
end
So with everything the way it is (hardcoded) the params are passed through and output in my preview view, but as soon as i try accessing the forms object/params nothing gets passed th
# Console Output
1 - link_to 'Preview', preview_my_admin_panel_posts_path(post: { title: f.object.title, comments: f.object.comments, category_id: f.object.category_id})
#<Post:0x007f8bbe1fc4c0 id: nil, title: "", comments: "", category_id: nil, slug: nil, published: 0, created_at: nil, updated_at: nil>
2 - link_to 'Preview', preview_my_admin_panel_posts_path(post: { title: f.title, comments: f.comments, category_id: f.category_id })
# Console Output
#<Post:0x007f8bbe1fc4c0 id: nil, title: nil, comments: nil, category_id: nil, slug: nil, published: 0, created_at: nil, updated_at: nil>
3 - link_to 'Preview', preview_my_admin_panel_posts_path(#post)
# Console Output
#<Post:0x007f8bbe1fc4c0 id: nil, title: nil, comments: nil, category_id: nil, slug: nil, published: 0, created_at: nil, updated_at: nil>
Not sure where else to go with this, f.object.param seems close but passing through empty strings? has anyone done this before ?
If anyone has an alternative solution would love to hear it.
Thanks
Update
When outputting params to the console i get this returned
{"action"=>"preview", "controller"=>"my_admin_panel/posts"}
Are you trying to create a post? When you load this page the fields do not have any value thus the link will not load any parameter(you can inspect element on the preview link and see that the link does not have any parameter).
One way is to use JavaScript to catch the value before the link has routed in controller.
class ChatMessage < ActiveResource::Base
alias_attribute :user_id, :userId
alias_attribute :chat_id, :chatId
alias_attribute :message_text, :MessageText
...
I Have the problem that what I return from an API has attribute names that I don't like, e.g. see camelCaps. I don't want to do this to every model in my application. Is there some method missing magic I could apply?
Cheers
Thomas
You can do a little of metaprogramming here:
module JavaAliasing
def initialize(hash)
super(Hash[hash.map do |k,v|
[k.to_s.gsub(/[a-z][A-Z]/) { |s| s.split('').join('_') }.downcase.to_sym, v]
end])
end
end
Let me illustrate this:
class Instantiator
def initialize(hash)
hash.each { |k,v| instance_variable_set "##{k}", v }
end
end
Instantiator.new(asdf: 2).instance_variable_get('#asdf') #=> 2
class MyARModel < Instantiator
include JavaAliasing
end
MyARModel.new(asdfQWER: 2).instance_variable_get("#asdf_qwer") #=> 2
Here, a real life example (rails 4.0):
> Player.send :include, JavaAliasing
> Player.new(name: 'pololo', username: 'asdf', 'teamId' => 23)
=> #<Player id: nil, name: "pololo", username: "asdf", email: nil, type: "Player", created_at: nil, updated_at: nil, provider: nil, uid: nil, team_id: 23, last_login: nil, last_activity: nil>
How to Rectify this error in RSpec for Controller,
1) SellersController GET index find the Activity
Failure/Error: assigns(:activity).should eq([activity])
expected: [#<Activity id: 65, transactable_type: "admin", transactable_id: 1, action_type: "seller", user_id: 1, is_approved: false, approved_by: nil, created_at: "2012-04-09 11:02:17", updated_at: "2012-04-09 11:02:17", associatable_type: nil, associatable_id: nil>]
got: nil
(compared using ==)
Seller_rspec.rb
describe "GET index" do
it "find the Activity" do
activity = Activity.create!(:transactable_type=>"admin",:transactable_id=>1,:action_type=>"seller",:user_id =>1,:is_approved=>0)
get :index,{:is_approved => activity.to_param,:user_id=>1,:approved_by=>"admin"}
assigns(:activity).should eq([activity])
end
In controller
def index
#activities=Activity.find(:all,:select => 'DISTINCT transactable_type,transactable_id,action_type,is_approved,approved_by',:conditions=>["is_approved= ? and user_id=? and approved_by IS NULL",false,current_user.id])
end
You are putting a code into controller which should go to the model. Create a method or scope in Activity model like:
def self.find_not_approved(current_user_id)
find(:all,
:select => 'DISTINCT transactable_type,transactable_id,action_type,is_approved,approved_by',
:conditions= ["is_approved= ? and user_id=? and approved_by IS NULL",
false,
current_user_id])
end
So you can just have in controller (I've made up the method name):
def index
#activities = Activity.find_not_appoved(current_user.id)
end
And just to anser your question, it should be assigns(:activities).should eq([activity]) not assigns(:activity).should eq([activity]) - as your are checking #activities variable in controller not, #activity.