So I'm trying to create a list of console commands for a game, and to make it slightly nicer I want to have three commands on a single line.
Example:
Commands.afk.Args.Name = "!afk";
Commands.transfer.Args.Name = "!transfer";
Commands.jump.Args.Name = "!jump";
Would be:
[ !afk ] [ !jump ] [ !transfer ]
I think I know how to do this (by using table.concat), but this code also requires to verify that the commands we're forwarding belong to the user's access group (we don't want to send them administrator commands if they're just a guest for instance).
Commands.[commandname].Args.Access returns a number between 1 and 6, which corresponds to the membership grade that the user belongs to. The function Core:GetAccess(player) (where player is the user's unique entity table) returns the membership group that the user belongs to- the Commands.[commandname].Args.Access and Core:GetAccess(player) need to match in order to allow the command to be listed.
I'm not too fussed about formatting at the moment, I'm just more concerned whether my specific usage case is actually possible or not.
If it is possible, can a simple table.concat be used?
I've looked on the internet for the solution to this, but nothing appears to match my specifric usage case.
table.concat only formats plain string items from array-like tables.
If you need to do more complicated work then that that you need to write some code yourself.
Something like the following might work:
local available_commands = {}
for cmd, tab in pairs(Commands) do
if cmd.Args.Access == Core:GetAccess(player) then
available_commands[#available_commands + 1] = "[!"..cmd.Args.Name.."]"
end
end
local display_string = table.concat(available_commands)
print(display_string)
You could just iterate through all commands and set it inside loop.
for i,v in pairs(Commands) do
v.Args=v.Args or {};
v.Args["name"]=i;
end
Just call this little loop right after you load all chat-commands.
Related
I'd like one of my models, Stones, to be generated at random using pre-defined options I've stored in a set of arrays and hashes. Instead of Create using params from the URL, I'd like new Stones to always be defined using this random generation process. I don't need any user input at all, except that each stone belongs to a given player.
I'm still new to rails; where should I put all this code? I know enough to be able to define the arrays and hashes and randomly select from them when I need to, but I'm not sure where and how to replace the part of the code that draws params from URLs and fills in a new record before it is saved. I know controllers are supposed to be skinny, so do I do this in the model?
Apologies if this is a duplicate. I searched extensively and couldn't find an applicable solution.
Thanks for any help!
I would create a service for this. Something like:
# app/services/stone_creator.rb
class RandomStoneCreator
RANDOM_FOOS = ['bar', 'baz', 'bat']
def self.call(user)
Stone.create!({
foo: RANDOM_FOOS.sample,
user: user
})
end
end
And then anywhere that you need a new random stone you can call it like:
random_stone = RandomStoneCreator.call(current_user)
I'm not sure if this is just a lacking of the Rails language, or if I am searching all the wrong things here on Stack Overflow, but I cannot find out how to add an attribute to each record in an array.
Here is an example of what I'm trying to do:
#news_stories.each do |individual_news_story|
#user_for_record = User.where(:id => individual_news_story[:user_id]).pluck('name', 'profile_image_url');
individual_news_story.attributes(:author_name) = #user_for_record[0][0]
individual_news_story.attributes(:author_avatar) = #user_for_record[0][1]
end
Any ideas?
If the NewsStory model (or whatever its name is) has a belongs_to relationship to User, then you don't have to do any of this. You can access the attributes of the associated User directly:
#news_stories.each do |news_story|
news_story.user.name # gives you the name of the associated user
news_story.user.profile_image_url # same for the avatar
end
To avoid an N+1 query, you can preload the associated user record for every news story at once by using includes in the NewsStory query:
NewsStory.includes(:user)... # rest of the query
If you do this, you won't need the #user_for_record query — Rails will do the heavy lifting for you, and you could even see a performance improvement, thanks to not issuing a separate pluck query for every single news story in the collection.
If you need to have those extra attributes there regardless:
You can select them as extra attributes in your NewsStory query:
NewsStory.
includes(:user).
joins(:user).
select([
NewsStory.arel_table[Arel.star],
User.arel_table[:name].as("author_name"),
User.arel_table[:profile_image_url].as("author_avatar"),
]).
where(...) # rest of the query
It looks like you're trying to cache the name and avatar of the user on the NewsStory model, in which case, what you want is this:
#news_stories.each do |individual_news_story|
user_for_record = User.find(individual_news_story.user_id)
individual_news_story.author_name = user_for_record.name
individual_news_story.author_avatar = user_for_record.profile_image_url
end
A couple of notes.
I've used find instead of where. find returns a single record identified by it's primary key (id); where returns an array of records. There are definitely more efficient ways to do this -- eager-loading, for one -- but since you're just starting out, I think it's more important to learn the basics before you dig into the advanced stuff to make things more performant.
I've gotten rid of the pluck call, because here again, you're just learning and pluck is a performance optimization useful when you're working with large amounts of data, and if that's what you're doing then activerecord has a batch api you should look into.
I've changed #user_for_record to user_for_record. The # denote instance variables in ruby. Instance variables are shared and accessible from any instance method in an instance of a class. In this case, all you need is a local variable.
I am new to Ruby for one project only - I need to join two tables with aws dynamodb. Basically the equivalent of sql left join. But since dynamodb apparently doesn't support I need to make it happen at the array level it seems.
Currently I am querying the one just fine, but I need to bring in this other table, but I'm having a heck of a time finding a simple example for ruby with rails without using ActiveRecord (to avoid causing an overhaul on pre-existing code).
client = Aws::DynamoDB::Client.new
response = client.scan(table_name: 'db_current')
#items = response.items
fake output to protect the innocent
db_current
{"machine_id"=>"pc-123435", "type_id"=>"t-56778"}
db_type
{"description"=>"Dell 5 Dev Computer", "Name"=>"Dell", "type_id"=>"t-56778"}
I thought I might have to make two:
client = Aws::DynamoDB::Client.new
db_c = client.scan(table_name: 'db_current')
#c_items = db_c.items
client = Aws::DynamoDB::Client.new
db_t = client.scan(table_name: 'db_type')
#t_items = db_c.joins(db_t['type_id']) <=== then merge them
here.
where I'll ultimately display description/name/machine_id
But sadly no luck.
I'm looking for suggestions. I'd prefer to keep it simple to really
understand (It might sound unreasonable, I don't want to pull in ActiveRecord just yet unless I'll be owning this project going forward).
I ended up doing it this way. There is probably a more elegant solution for those that are familiar with Ruby... that I am not.
basically for each of the items in the first hash array (table), I use the ID from that one to filter on the item for the 2nd hash array. Merging them in the process. then appending to a final destination which I'll use for my UI.
#c_by_id = Array.new
#b_items.each do |item|
pjoin = #c_items.first {|h| h['b_id'] == item['b_id']}
newjoin = item.merge(pjoin)
#c_by_id.append(newjoin)
end
There was a very similar question before but i still struggle.
Is it possible to build a query up in stages?
Let's say I have a search form with many text and select fields that may be chained with and/or or which could be blank.
So the sql statement should consist of several parts that are connected individually for each search.
I tried to create strings for every option and put them to a symbol? (i mean #options) and put that in the where clause (e.g. Product.where(#options) ). That works somehow but i have got troubles with this part: 'params[:query]' when it's in quotes. Either my sql statement says 'select products from products where (name like params[:query]') or if i try #{params[:query]} it says: select products from products (where 'name' like ''.)
So how can i chain different parts of a query?
I looking forward to your answers!
Never, ever, ever embed raw strings in your SQL. This is extremely bad form. You should always use the escaping mechanism provided by Rails or something equivalent to avoid ending up in serious trouble. Inserting content from params is very dangerous and should never be done as it only takes this to nuke your app: { :query => '\"-- DROP TABLE users;' }
Generally you use the helper methods provided by ActiveRecord to build up your query in stages:
scope = Product
if (params[:query].present?)
scope = scope.where([ 'name LIKE ?', "%#{params[:query]}%" ])
end
if (params[:example].present?)
scope = scope.where(:example => true)
end
#products = scope.all
You can build it up in stages like this, modifying the scope in-place each time, and then execute the final call to retrieve it. Generally that's when you use your paginator to split up the results.
It's okay to put pretty much anything in your options because it should be escaped by the time it hits the SQL phase, much as anything on the HTML side is escaped for you as well.
Don't confuse instance variables like #options with a symbol like :query. The two are very different things. Instance variables have the benefit of propagating to your view automatically, so they are often used extensively in controllers. Views should avoid modifying them whenever possible as a matter of style.
Yet another ruby question but this is a bunch of questions in one. I'm really starting to like rails but there are some questions that I'd just like to ask straight out.
Right now, I'm implementing a queue in sqlite. I already have a scaffold setup with this working OK. The purpose is for a web crawler to read through the array and determine which links he should crawl next.
The architecture in the program is 2 controllers. one for Job and one for crawler. The Jobs has the standard Crud interface supplied by scaffold. Where I'm falling down is I'm still trying to understand how these things communicate with eachother.
The Job is formatted as a url:string and depth:decimal. The table is already populated with about 4 objects.
#sitesToCrawl = Job.all
#sitesToCrawl.each {|x|puts Job.url}
I have a bunch of questions about the above.
At the moment, this was supposed to display all the jobs and I foolishly thought it would display plain text but its actually a hexidecimal pointer to the object itself. What Im trying to do is iterate through the #sitesToCrawl and put out each Jobs url.
Questions start here:
1: I know ruby is dynamically typed. Will #sitesToCrawl become an array like i want it to be with each slot containing a job.
2: #sitesToCrawl.each is pretty straighforward and I'm assuming its an iterator.
is X the name od the method or what is the purpose of the symbol or string between |*|
3: Puts and print are more or less the same yes? if i say #x = puts 3 then would x be 3?
4: Job.url. Can objects be referenced this way or should I be using
##sitesToCrawl = db.execute("SELECT url FROM jobs;")
where db is a new database
As Rubish Gupta pointed out, in your block, you should do x.url, otherwise you're trying to access the url method on the class Job, not on instances of Job. In other words, in blocks, the items in the pipes are the arguments of the block, and each will iterate through your array, passing in one item at a time to your block. Check out the doc here.
Just to extend this idea, each on Hashes (associative arrays, maps, whatever you know them as) will pass two variables to your block: a key and a value, like this:
a_hash.each {|key_var, val_var| puts "#{key_var} is associated with #{val_var}"}
Also, it's been a bit since I've done plain ActiveRecord models, but you might look into doing
#sitesToCrawl = Job.all.to_a
since Job.all is a lazy finder in that it's building a query in potentia: you've essentially built a query string saying SELECT * FROM jobs, but it might not be executed until you try to access the items. each might do that, I can't remember off the top of my head, but if you're using a debugger to look at it, I know you need to_a to get it to run the query.
You should absolutely be using job_instance.url - that's the beauty of ActiveRecord, it makes database access easy, provided everything gets set up right :)
Finally, puts and print are almost the same - the difference is that puts "string" is essentialy print "sting"; STDOUT.flush - it flushes at the end of the statement.